Tickets! and a lot of bug fixes
diff --git a/src/Unfinished/all.ts b/src/Unfinished/all.ts
index 4fd1202..9d9e653 100644
--- a/src/Unfinished/all.ts
+++ b/src/Unfinished/all.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../utils/defaults.js";
 import Discord, {
     CommandInteraction,
     GuildMember,
diff --git a/src/Unfinished/categorisationTest.ts b/src/Unfinished/categorisationTest.ts
index f5660fe..dc38dfe 100644
--- a/src/Unfinished/categorisationTest.ts
+++ b/src/Unfinished/categorisationTest.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../utils/defaults.js";
 import { CommandInteraction, GuildChannel, ActionRowBuilder, ButtonBuilder, SelectMenuBuilder, ButtonStyle } from "discord.js";
 import { SlashCommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../utils/generateEmojiEmbed.js";
@@ -84,7 +84,10 @@
         });
         let i;
         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) {
             return await interaction.editReply({
                 embeds: [
@@ -118,7 +121,7 @@
     console.log(categorised);
 };
 
-const check = (_interaction: CommandInteraction) => {
+const check = () => {
     return true;
 };
 
diff --git a/src/actions/roleMenu.ts b/src/actions/roleMenu.ts
index 1c493bb..3a01c46 100644
--- a/src/actions/roleMenu.ts
+++ b/src/actions/roleMenu.ts
@@ -1,10 +1,24 @@
-import { Interaction, ButtonBuilder, CommandInteraction, Role, ButtonStyle, ButtonInteraction } from "discord.js";
+import { unknownServerIcon } from './../utils/defaults.js';
+import {
+    Interaction,
+    ButtonBuilder,
+    CommandInteraction,
+    ButtonStyle,
+    ButtonInteraction,
+    StringSelectMenuOptionBuilder,
+    StringSelectMenuBuilder,
+    GuildMemberRoleManager,
+    Role
+} from "discord.js";
 import EmojiEmbed from "../utils/generateEmojiEmbed.js";
-import { ActionRowBuilder, SelectMenuBuilder } from "discord.js";
+import { ActionRowBuilder } from "discord.js";
 import getEmojiByName from "../utils/getEmojiByName.js";
 import client from "../utils/client.js";
-import { LoadingEmbed } from "../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../utils/defaults.js";
 import type { GuildConfig } from "../utils/database.js";
+import { roleException } from '../utils/createTemporaryStorage.js';
+import addPlural from '../utils/plurals.js';
+import createPageIndicator from '../utils/createPageIndicator.js';
 
 export interface RoleMenuSchema {
     guild: string;
@@ -17,19 +31,17 @@
 }
 
 export async function callback(interaction: CommandInteraction | ButtonInteraction) {
-    if(!interaction.guild) return interaction.reply({ content: "This command can only be used in a server.", ephemeral: true });
-    if(!interaction.member) return interaction.reply({ content: "You must be in a server to use this command.", ephemeral: true });
+    if (!interaction.member) return;
+    if (!interaction.guild) return;
     const config = await client.database.guilds.read(interaction.guild.id);
     if (!config.roleMenu.enabled)
         return await interaction.reply({
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Roles")
-                    .setDescription(
-                        "Self roles are currently disabled. Please contact a staff member or try again later."
-                    )
+                    .setDescription("Self roles are currently disabled. Please contact a staff member or try again later.")
                     .setStatus("Danger")
-                    .setEmoji("CONTROL.BLOCKCROSS")
+                    .setEmoji("GUILD.GREEN")
             ],
             ephemeral: true
         });
@@ -38,167 +50,187 @@
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Roles")
-                    .setDescription("There are no roles available. Please contact a staff member or try again later.")
+                    .setDescription("There are no roles available. Please contact a staff member if you believe this is a mistake.")
                     .setStatus("Danger")
-                    .setEmoji("CONTROL.BLOCKCROSS")
+                    .setEmoji("GUILD.GREEN")
             ],
             ephemeral: true
         });
-    await interaction.reply({ embeds: LoadingEmbed, ephemeral: true });
-    let m;
-    if (config.roleMenu.allowWebUI) {
-        let code = "";
-        let length = 5;
-        let itt = 0;
-        const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-        let valid = false;
-        while (!valid) {
-            itt += 1;
-            code = "";
-            for (let i = 0; i < length; i++) {
-                code += chars.charAt(Math.floor(Math.random() * chars.length));
-            }
-            if (code in client.roleMenu) continue;
-            if (itt > 1000) {
-                itt = 0;
-                length += 1;
-                continue;
-            }
-            valid = true;
+    const m = await interaction.reply({ embeds: LoadingEmbed, ephemeral: true });
+    if (config.roleMenu.allowWebUI) {  // TODO: Make rolemenu web ui
+        const loginMethods: {webUI: boolean} = {
+            webUI: false
         }
-        client.roleMenu[code] = {
-            guild: interaction.guild.id,
-            guildName: interaction.guild.name,
-            guildIcon: interaction.guild.iconURL({ extension: "png" }),
-            user: interaction.member.user.id,
-            username: interaction.member.user.username,
-            data: config.roleMenu.options,
-            interaction: interaction
-        };
-        let up = true;
-        up = false; // FIXME: Role menu does not yet exist, so the web UI is never up
-        /*        try {
+        try {
             const status = await fetch(client.config.baseUrl).then((res) => res.status);
-            if (status !== 200) up = false;
-        } catch {
-            up = false;
-        }*/
-        m = await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Roles")
-                    .setDescription("Select how to choose your roles")
-                    .setStatus("Success")
-                    .setEmoji("GUILD.GREEN")
-            ],
-            components: [
-                new ActionRowBuilder().addComponents([
-                    new ButtonBuilder()
-                        .setLabel("Online")
-                        .setStyle(ButtonStyle.Link)
-                        .setDisabled(!up)
-                        .setURL(`${client.config.baseUrl}nucleus/rolemenu?code=${code}`),
-                    new ButtonBuilder().setLabel("Manual").setStyle(ButtonStyle.Primary).setCustomId("manual")
-                ])
-            ]
-        });
-    }
-    let component;
-    if (!m) return;
-    try {
-        component = await m.awaitMessageComponent({ time: 300000 });
-    } catch (e) {
-        return;
-    }
-    component.deferUpdate();
-    let rolesToAdd: Role[] = [];
-    for (let i = 0; i < config.roleMenu.options.length; i++) {
-        const object = config.roleMenu.options[i];
-        const m = await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Roles")
-                    .setEmoji("GUILD.GREEN")
-                    .setDescription(
-                        `**${object.name}**` +
-                            (object.description ? `\n${object.description}` : "") +
-                            `\n\nSelect ${object.min}` +
-                            (object.min !== object.max ? ` to ${object.max}` : "") +
-                            ` role${object.max === 1 ? "" : "s"} to add.`
-                    )
-                    .setStatus("Success")
-                    .setFooter({
-                        text: `Step ${i + 1}/${config.roleMenu.options.length}`
-                    })
-            ],
-            components: [
-                new ActionRowBuilder().addComponents(
-                    [
+            if (status !== 200) loginMethods.webUI = false;
+        } catch(e) {
+            loginMethods.webUI = false;
+        }
+        if (Object.values(loginMethods).some((i) => i)) {
+            let code = "";
+            if (loginMethods.webUI) {
+                let length = 5;
+                let itt = 0;
+                const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+                let valid = false;
+                while (!valid) {
+                    itt += 1;
+                    code = "";
+                    for (let i = 0; i < length; i++) {
+                        code += chars.charAt(Math.floor(Math.random() * chars.length));
+                    }
+                    if (code in client.roleMenu) continue;
+                    if (itt > 1000) {
+                        itt = 0;
+                        length += 1;
+                        continue;
+                    }
+                    valid = true;
+                }
+                client.roleMenu[code] = {
+                    guild: interaction.guild.id,
+                    guildName: interaction.guild.name,
+                    guildIcon: interaction.guild.iconURL({ extension: "png" }) ?? unknownServerIcon,
+                    user: interaction.member!.user.id,
+                    username: interaction.member!.user.username,
+                    data: config.roleMenu.options,
+                    interaction: interaction as Interaction
+                };
+            }
+            await interaction.editReply({
+                embeds: [
+                    new EmojiEmbed()
+                        .setTitle("Roles")
+                        .setDescription("Select how to choose your roles")
+                        .setStatus("Success")
+                        .setEmoji("GUILD.GREEN")
+                ],
+                components: [
+                    new ActionRowBuilder<ButtonBuilder>().addComponents([
                         new ButtonBuilder()
-                            .setLabel("Cancel")
-                            .setStyle(ButtonStyle.Danger)
-                            .setCustomId("cancel")
-                            .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
-                    ].concat(
-                        object.min === 0
-                            ? [
-                                  new ButtonBuilder()
-                                      .setLabel("Skip")
-                                      .setStyle(ButtonStyle.Secondary)
-                                      .setCustomId("skip")
-                                      .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
-                              ]
-                            : []
-                    )
-                )
-            ].concat([
-                new ActionRowBuilder().addComponents([
-                    new SelectMenuBuilder()
-                        .setPlaceholder(`${object.name}`)
-                        .setCustomId("rolemenu")
-                        .setMinValues(object.min)
-                        .setMaxValues(object.max)
-                        .setOptions(
-                            object.options.map((o) => {
-                                return {
-                                    label: o.name,
-                                    description: o.description,
-                                    value: o.role
-                                };
-                            })
-                        )
-                ])
-            ])
+                            .setLabel("Online")
+                            .setStyle(ButtonStyle.Link)
+                            .setDisabled(!loginMethods.webUI)
+                            .setURL(`${client.config.baseUrl}nucleus/rolemenu?code=${code}`),
+                        new ButtonBuilder()
+                            .setLabel("In Discord")
+                            .setStyle(ButtonStyle.Primary)
+                            .setCustomId("discord")
+                    ])
+                ]
+            });
+            let component;
+            try {
+                component = await m.awaitMessageComponent({
+                    time: 300000,
+                    filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
+                });
+            } catch (e) {
+                return;
+            }
+            component.deferUpdate();
+        }
+    }
+
+    const options = config.roleMenu.options;
+    const selectedRoles: string[][] = [];
+    const maxPage = options.length;
+    const completedPages: boolean[] = options.map((option) => option.min === 0);
+    for (let i = 0; i < maxPage; i++) { selectedRoles.push([]); }
+
+    let page = 0;
+    let complete = completedPages.every((page) => page);
+    let done = false;
+
+    while (!(complete && done)) {
+        const currentPageData = options[page]!
+        const embed = new EmojiEmbed()
+            .setTitle("Roles")
+            .setDescription(
+                `**${currentPageData.name}**\n` +
+                `> ${currentPageData.description}\n\n` +
+                (currentPageData.min === currentPageData.max ? `Select ${addPlural(currentPageData.min, "role")}` :
+                    `Select between ${currentPageData.min} and ${currentPageData.max} roles` + (
+                        currentPageData.min === 0 ? ` or press next` : "")) + "\n\n" +
+                createPageIndicator(maxPage, page)
+            )
+            .setStatus("Success")
+            .setEmoji("GUILD.GREEN");
+        const components = [
+            new ActionRowBuilder<ButtonBuilder>().addComponents(
+                new ButtonBuilder()
+                    .setStyle(ButtonStyle.Secondary)
+                    .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+                    .setCustomId("back")
+                    .setDisabled(page === 0),
+                new ButtonBuilder()
+                    .setStyle(ButtonStyle.Secondary)
+                    .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
+                    .setCustomId("next")
+                    .setDisabled(page === maxPage - 1),
+                new ButtonBuilder()
+                    .setStyle(ButtonStyle.Success)
+                    .setEmoji(getEmojiByName("CONTROL.TICK", "id"))
+                    .setCustomId("done")
+                    .setDisabled(!complete)
+            ),
+            new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
+                new StringSelectMenuBuilder()
+                    .setCustomId("roles")
+                    .setPlaceholder("Select...")
+                    .setMinValues(currentPageData.min)
+                    .setMaxValues(currentPageData.max)
+                    .addOptions(currentPageData.options.map((option) => {
+                        const builder = new StringSelectMenuOptionBuilder()
+                            .setLabel(option.name)
+                            .setValue(option.role)
+                            .setDefault(selectedRoles[page]!.includes(option.role));
+                        if (option.description) builder.setDescription(option.description);
+                        return builder;
+                    }))
+            )
+        ];
+        await interaction.editReply({
+            embeds: [embed],
+            components: components
         });
         let component;
         try {
-            component = await m.awaitMessageComponent({ time: 300000 });
+            component = await m.awaitMessageComponent({
+                time: 300000,
+                filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
+            });
         } catch (e) {
             return;
         }
         component.deferUpdate();
-        if (component.customId === "rolemenu") {
-            rolesToAdd = rolesToAdd.concat(component.values);
-        } else if (component.customId === "cancel") {
-            return await interaction.editReply({
-                embeds: [
-                    new EmojiEmbed()
-                        .setTitle("Roles")
-                        .setDescription("Cancelled. No changes were made.")
-                        .setStatus("Danger")
-                        .setEmoji("GUILD.RED")
-                ],
-                components: []
-            });
+        if (component.customId === "back") {
+            page = Math.max(0, page - 1);
+        } else if (component.customId === "next") {
+            page = Math.min(maxPage - 1, page + 1);
+        } else if (component.customId === "done") {
+            done = true;
+        } else if (component.customId === "roles" && component.isStringSelectMenu()) {
+            selectedRoles[page] = component.values;
+            completedPages[page] = true
+            page = Math.min(maxPage - 1, page + 1);
         }
+        complete = completedPages.every((page) => page);
     }
-    let rolesToRemove = config.roleMenu.options.map((o) => o.options.map((o) => o.role)).flat();
-    const memberRoles = interaction.member.roles.cache.map((r) => r.id);
-    rolesToRemove = rolesToRemove.filter((r) => memberRoles.includes(r)).filter((r) => !rolesToAdd.includes(r));
-    rolesToAdd = rolesToAdd.filter((r) => !memberRoles.includes(r));
+
+    const fullRoleList: string[] = selectedRoles.flat();
+
+    const memberRoles = (interaction.member.roles as GuildMemberRoleManager).cache.map((r) => r.id);  // IDs
+    let rolesToRemove = config.roleMenu.options.map((o) => o.options.map((o) => o.role)).flat();  // IDs
+    rolesToRemove = rolesToRemove.filter((r) => memberRoles.includes(r)).filter((r) => !fullRoleList.includes(r))  // IDs
+    let roleObjectsToAdd = fullRoleList.map((r) => interaction.guild!.roles.cache.get(r))  // Role objects
+        .filter((r) => r !== undefined) as Role[];
+    roleObjectsToAdd = roleObjectsToAdd.filter((r) => !memberRoles.includes(r.id));  // Role objects
     try {
-        await interaction.member.roles.remove(rolesToRemove);
-        await interaction.member.roles.add(rolesToAdd);
+        roleException(interaction.guild.id, interaction.user.id)
+        await (interaction.member.roles as GuildMemberRoleManager).remove(rolesToRemove);
+        await (interaction.member.roles as GuildMemberRoleManager).add(roleObjectsToAdd);
     } catch (e) {
         return await interaction.reply({
             embeds: [
@@ -217,7 +249,7 @@
         embeds: [
             new EmojiEmbed()
                 .setTitle("Roles")
-                .setDescription("Roles have been added. You may close this message.")
+                .setDescription("Roles have been updated")
                 .setStatus("Success")
                 .setEmoji("GUILD.GREEN")
         ],
diff --git a/src/actions/tickets/create.ts b/src/actions/tickets/create.ts
index 595a5b3..3c2dd2c 100644
--- a/src/actions/tickets/create.ts
+++ b/src/actions/tickets/create.ts
@@ -3,16 +3,16 @@
 import client from "../../utils/client.js";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
+import { getCommandMentionByName } from "../../utils/getCommandMentionByName.js";
 
 function capitalize(s: string) {
     s = s.replace(/([A-Z])/g, " $1");
-    return s.length < 3 ? s.toUpperCase() : s[0].toUpperCase() + s.slice(1).toLowerCase();
+    return s.length < 3 ? s.toUpperCase() : s[0]!.toUpperCase() + s.slice(1).toLowerCase();
 }
 
 export default async function (interaction: CommandInteraction | ButtonInteraction) {
     if (!interaction.guild) return;
     const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
-
     const config = await client.database.guilds.read(interaction.guild.id);
     if (!config.tickets.enabled || !config.tickets.category) {
         return await interaction.reply({
@@ -21,7 +21,7 @@
                     .setTitle("Tickets are disabled")
                     .setDescription("Please enable tickets in the configuration to use this command.")
                     .setFooter({
-                        text: interaction.member.permissions.has("MANAGE_GUILD")
+                        text: (interaction.member!.permissions as Discord.PermissionsBitField).has("ManageGuild")
                             ? "You can enable it by running /settings tickets"
                             : ""
                     })
@@ -31,16 +31,26 @@
             ephemeral: true
         });
     }
-    const category = interaction.guild.channels.cache.get(config.tickets.category) as Discord.CategoryChannel;
     let count = 0;
-    category.children.forEach((element) => {
-        if (!(element.type === "GUILD_TEXT")) return;
-        if ((element as Discord.TextChannel).topic.includes(`${interaction.member.user.id}`)) {
-            if ((element as Discord.TextChannel).topic.endsWith("Active")) {
-                count++;
+    const targetChannel: Discord.CategoryChannel | Discord.TextChannel = (await interaction.guild.channels.fetch(config.tickets.category))! as Discord.CategoryChannel | Discord.TextChannel;
+    if (targetChannel.type === Discord.ChannelType.GuildCategory) {
+        // For channels, the topic is the user ID, then the word Active
+        const category = targetChannel as Discord.CategoryChannel;
+        category.children.cache.forEach((element) => {
+            if (!(element.type === Discord.ChannelType.GuildText)) return;
+            if (((element as Discord.TextChannel).topic ?? "").includes(`${interaction.member!.user.id}`)) {
+                if (((element as Discord.TextChannel).topic ?? "").endsWith("Active")) { count++; }
             }
-        }
-    });
+        });
+    } else {
+        // For threads, the name is the users name, id, then the word Active
+        const channel = targetChannel as Discord.TextChannel;
+        channel.threads.cache.forEach((element: Discord.ThreadChannel) => {
+            if (element.name.includes(`${interaction.member!.user.id}`)) {
+                if (element.name.endsWith("Active")) { count++; }
+            }
+        });
+    }
     if (count >= config.tickets.maxTickets) {
         return await interaction.reply({
             embeds: [
@@ -55,15 +65,15 @@
             ephemeral: true
         });
     }
-    let ticketTypes;
+    let ticketTypes: string[];
     let custom = false;
     if (config.tickets.customTypes && config.tickets.useCustom) {
         ticketTypes = config.tickets.customTypes;
         custom = true;
     } else if (config.tickets.types) ticketTypes = toHexArray(config.tickets.types, tickets);
     else ticketTypes = [];
-    let chosenType;
-    let splitFormattedTicketTypes = [];
+    let chosenType: string | null;
+    let splitFormattedTicketTypes: ActionRowBuilder<ButtonBuilder>[] = [];
     if (ticketTypes.length > 0) {
         let formattedTicketTypes = [];
         formattedTicketTypes = ticketTypes.map((type) => {
@@ -78,7 +88,7 @@
             }
         });
         for (let i = 0; i < formattedTicketTypes.length; i += 5) {
-            splitFormattedTicketTypes.push(new ActionRowBuilder().addComponents(formattedTicketTypes.slice(i, i + 5)));
+            splitFormattedTicketTypes.push(new ActionRowBuilder<ButtonBuilder>().addComponents(formattedTicketTypes.slice(i, i + 5)));
         }
         const m = await interaction.reply({
             embeds: [
@@ -94,7 +104,10 @@
         });
         let component;
         try {
-            component = await m.awaitMessageComponent({ time: 300000 });
+            component = await m.awaitMessageComponent({
+                time: 300000,
+                filter: (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
+            });
         } catch (e) {
             return;
         }
@@ -118,7 +131,7 @@
             }
         });
         for (let i = 0; i < formattedTicketTypes.length; i += 5) {
-            splitFormattedTicketTypes.push(new ActionRowBuilder().addComponents(formattedTicketTypes.slice(i, i + 5)));
+            splitFormattedTicketTypes.push(new ActionRowBuilder<ButtonBuilder>().addComponents(formattedTicketTypes.slice(i, i + 5)));
         }
         component.update({
             embeds: [
@@ -138,107 +151,190 @@
             components: splitFormattedTicketTypes
         });
     }
-    const overwrites = [
-        {
-            id: interaction.member,
-            allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
-            type: "member"
-        }
-    ] as Discord.OverwriteResolvable[];
-    overwrites.push({
-        id: interaction.guild.roles.everyone,
-        deny: ["VIEW_CHANNEL"],
-        type: "role"
-    });
-    if (config.tickets.supportRole !== null) {
+    let c: Discord.TextChannel | Discord.PrivateThreadChannel;
+    if (targetChannel.type === Discord.ChannelType.GuildCategory) {
+        const overwrites = [
+            {
+                id: interaction.member,
+                allow: ["ViewChannel", "SendMessages", "AttachFiles", "AddReactions", "ReadMessageHistory"],
+                type: Discord.OverwriteType.Member
+            }
+        ] as Discord.OverwriteResolvable[];
         overwrites.push({
-            id: interaction.guild.roles.cache.get(config.tickets.supportRole),
-            allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
-            type: "role"
+            id: interaction.guild.roles.everyone,
+            deny: ["ViewChannel"],
+            type: Discord.OverwriteType.Role
         });
-    }
+        if (config.tickets.supportRole !== null) {
+            overwrites.push({
+                id: interaction.guild.roles.cache.get(config.tickets.supportRole)!,
+                allow: ["ViewChannel", "SendMessages", "AttachFiles", "AddReactions", "ReadMessageHistory"],
+                type: Discord.OverwriteType.Role
+            });
+        }
 
-    let c;
-    try {
-        c = await interaction.guild.channels.create(interaction.member.user.username, {
-            type: "GUILD_TEXT",
-            topic: `${interaction.member.user.id} Active`,
-            parent: config.tickets.category,
-            nsfw: false,
-            permissionOverwrites: overwrites as Discord.OverwriteResolvable[],
-            reason: "Creating ticket"
-        });
-    } catch (e) {
-        return await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Create Ticket")
-                    .setDescription("Failed to create ticket")
-                    .setStatus("Danger")
-                    .setEmoji("CONTROL.BLOCKCROSS")
-            ]
-        });
-    }
-    try {
-        await c.send({
-            content:
-                `<@${interaction.member.user.id}>` +
-                (config.tickets.supportRole !== null ? ` • <@&${config.tickets.supportRole}>` : ""),
-            allowedMentions: {
-                users: [(interaction.member as Discord.GuildMember).id],
-                roles: config.tickets.supportRole !== null ? [config.tickets.supportRole] : []
+        try {
+            c = await interaction.guild.channels.create({
+                name: `${interaction.member!.user.username.toLowerCase()}`,
+                type: Discord.ChannelType.GuildText,
+                topic: `${interaction.member!.user.id} Active`,
+                parent: config.tickets.category,
+                nsfw: false,
+                permissionOverwrites: overwrites as Discord.OverwriteResolvable[],
+                reason: "Creating ticket"
+            });
+        } catch (e) {
+            return await interaction.editReply({
+                embeds: [
+                    new EmojiEmbed()
+                        .setTitle("Create Ticket")
+                        .setDescription("Failed to create ticket")
+                        .setStatus("Danger")
+                        .setEmoji("CONTROL.BLOCKCROSS")
+                ]
+            });
+        }
+        try {
+            await c.send({
+                content:
+                    `<@${interaction.member!.user.id}>` +
+                    (config.tickets.supportRole !== null ? ` • <@&${config.tickets.supportRole}>` : ""),
+                allowedMentions: {
+                    users: [(interaction.member as Discord.GuildMember).id],
+                    roles: config.tickets.supportRole !== null ? [config.tickets.supportRole] : []
+                }
+            });
+            let content: string | null = null;
+            if (interaction.isCommand()) {
+                content = interaction.options.get("message")?.value as string;
             }
-        });
-        let content = interaction.options ? interaction.options.getString("message") || "" : "";
-        if (content) content = `**Message:**\n> ${content}\n`;
-        const emoji = custom ? "" : getEmojiByName("TICKETS." + chosenType.toUpperCase());
-        await c.send({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("New Ticket")
-                    .setDescription(
-                        `Ticket created by <@${interaction.member.user.id}>\n` +
-                            `**Support type:** ${
-                                chosenType !== null ? emoji + " " + capitalize(chosenType) : "General"
-                            }\n` +
-                            `**Ticket ID:** \`${c.id}\`\n${content}\n` +
-                            "Type `/ticket close` to close this ticket."
-                    )
-                    .setStatus("Success")
-                    .setEmoji("GUILD.TICKET.OPEN")
-            ],
-            components: [
-                new ActionRowBuilder().addComponents([
-                    new ButtonBuilder()
-                        .setLabel("Close")
-                        .setStyle(ButtonStyle.Danger)
-                        .setCustomId("closeticket")
-                        .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
-                ])
-            ]
-        });
-        const data = {
-            meta: {
-                type: "ticketCreate",
-                displayName: "Ticket Created",
-                calculateType: "ticketUpdate",
-                color: NucleusColors.green,
-                emoji: "GUILD.TICKET.OPEN",
-                timestamp: new Date().getTime()
-            },
-            list: {
-                ticketFor: entry(interaction.member.user.id, renderUser(interaction.member.user)),
-                created: entry(new Date().getTime(), renderDelta(new Date().getTime())),
-                ticketChannel: entry(c.id, renderChannel(c))
-            },
-            hidden: {
-                guild: interaction.guild.id
+            if (content) content = `**Message:**\n> ${content}\n`;
+            let emoji;
+            if (chosenType) {
+                emoji = custom ? "" : getEmojiByName("TICKETS." + chosenType.toUpperCase());
+            } else {
+                emoji = "";
             }
-        };
-        log(data);
-    } catch (e) {
-        console.log(e);
+            await c.send({
+                embeds: [
+                    new EmojiEmbed()
+                        .setTitle("New Ticket")
+                        .setDescription(
+                            `Ticket created by <@${interaction.member!.user.id}>\n` +
+                                `**Support type:** ${
+                                    chosenType !== null ? emoji + " " + capitalize(chosenType) : "General"
+                                }\n` +
+                                `**Ticket ID:** \`${c.id}\`\n${content ?? ""}\n` +
+                                `Type ${await getCommandMentionByName("ticket/close")} to close this ticket.`
+                        )
+                        .setStatus("Success")
+                        .setEmoji("GUILD.TICKET.OPEN")
+                ],
+                components: [
+                    new ActionRowBuilder<ButtonBuilder>().addComponents([
+                        new ButtonBuilder()
+                            .setLabel("Close")
+                            .setStyle(ButtonStyle.Danger)
+                            .setCustomId("closeticket")
+                            .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+                    ])
+                ]
+            });
+        } catch (e) {
+            return await interaction.editReply({
+                embeds: [
+                    new EmojiEmbed()
+                        .setTitle("Create Ticket")
+                        .setDescription("Failed to create ticket")
+                        .setStatus("Danger")
+                        .setEmoji("GUILD.TICKET.CLOSE")
+                ]
+            });
+        }
+    } else {
+        c = await targetChannel.threads.create({name: `${interaction.member!.user.username} - ${interaction.member!.user.id} - Active`,
+                                                autoArchiveDuration: 60 * 24 * 7,
+                                                type: Discord.ChannelType.PrivateThread,
+                                                reason: "Creating ticket"
+                                                }) as Discord.PrivateThreadChannel;
+        c.members.add(interaction.member!.user.id);  // TODO: When a thread is used, and a support role is added, automatically set channel permissions
+        try {
+            await c.send({
+                content:
+                    `<@${interaction.member!.user.id}>` +
+                    (config.tickets.supportRole !== null ? ` • <@&${config.tickets.supportRole}>` : ""),
+                allowedMentions: {
+                    users: [(interaction.member as Discord.GuildMember).id],
+                    roles: config.tickets.supportRole !== null ? [config.tickets.supportRole] : []
+                }
+            });
+            let content: string | null = null;
+            if (interaction.isCommand()) {
+                content = interaction.options.get("message")?.value as string;
+            }
+            if (content) content = `**Message:**\n> ${content}\n`;
+            let emoji;
+            if (chosenType) {
+                emoji = custom ? "" : getEmojiByName("TICKETS." + chosenType.toUpperCase());
+            } else {
+                emoji = "";
+            }
+            await c.send({
+                embeds: [
+                    new EmojiEmbed()
+                        .setTitle("New Ticket")
+                        .setDescription(
+                            `Ticket created by <@${interaction.member!.user.id}>\n` +
+                                `**Support type:** ${
+                                    chosenType !== null ? emoji + " " + capitalize(chosenType) : "General"
+                                }\n` +
+                                `**Ticket ID:** \`${c.id}\`\n${content ?? ""}\n` +
+                                `Type ${await getCommandMentionByName("ticket/close")} to close this ticket.`
+                        )
+                        .setStatus("Success")
+                        .setEmoji("GUILD.TICKET.OPEN")
+                ],
+                components: [
+                    new ActionRowBuilder<ButtonBuilder>().addComponents([
+                        new ButtonBuilder()
+                            .setLabel("Close")
+                            .setStyle(ButtonStyle.Danger)
+                            .setCustomId("closeticket")
+                            .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+                    ])
+                ]
+            });
+        } catch (e) {
+            return await interaction.editReply({
+                embeds: [
+                    new EmojiEmbed()
+                        .setTitle("Create Ticket")
+                        .setDescription("Failed to create ticket")
+                        .setStatus("Danger")
+                        .setEmoji("GUILD.TICKET.CLOSE")
+                ]
+            });
+        }
     }
+    const data = {
+        meta: {
+            type: "ticketCreate",
+            displayName: "Ticket Created",
+            calculateType: "ticketUpdate",
+            color: NucleusColors.green,
+            emoji: "GUILD.TICKET.OPEN",
+            timestamp: new Date().getTime()
+        },
+        list: {
+            ticketFor: entry(interaction.member!.user.id, renderUser(interaction.member!.user! as Discord.User)),
+            created: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+            ticketChannel: entry(c.id, renderChannel(c))
+        },
+        hidden: {
+            guild: interaction.guild.id
+        }
+    };
+    log(data);
     await interaction.editReply({
         embeds: [
             new EmojiEmbed()
diff --git a/src/actions/tickets/delete.ts b/src/actions/tickets/delete.ts
index cab38ec..48d2a51 100644
--- a/src/actions/tickets/delete.ts
+++ b/src/actions/tickets/delete.ts
@@ -1,50 +1,52 @@
-import Discord, { ButtonBuilder, ActionRowBuilder, ButtonStyle, ButtonInteraction } from "discord.js";
+import { getCommandMentionByName } from '../../utils/getCommandMentionByName.js';
+import Discord, { ActionRowBuilder, ButtonBuilder, ButtonInteraction, PrivateThreadChannel, TextChannel, ButtonStyle } from "discord.js";
 import client from "../../utils/client.js";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
+import { preloadPage } from '../../utils/createTemporaryStorage.js';
 
 export default async function (interaction: Discord.CommandInteraction | ButtonInteraction) {
     if (!interaction.guild) return;
+    const config = await client.database.guilds.read(interaction.guild.id);
     const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger;
 
-    const config = await client.database.guilds.read(interaction.guild.id);
-    let thread = false;
-    if (interaction.channel instanceof Discord.ThreadChannel) thread = true;
-    const threadChannel = interaction.channel as Discord.ThreadChannel;
-    const channel = interaction.channel as Discord.TextChannel;
-    if (
-        !channel.parent ||
-        config.tickets.category !== channel.parent.id ||
-        (thread ? threadChannel.parent.parent.id !== config.tickets.category : false)
-    ) {
-        return interaction.reply({
+    const ticketChannel = config.tickets.category;
+    if (!("parent" in interaction.channel!)) {
+        return await interaction.reply({
             embeds: [
                 new EmojiEmbed()
-                    .setTitle("Deleting Ticket...")
-                    .setDescription(
-                        "This ticket is not in your tickets category, so cannot be deleted. You cannot run close in a thread."
-                    )
+                    .setTitle("Not a ticket")
+                    .setDescription("This channel isn't a ticket, so you can't delete it.")
                     .setStatus("Danger")
                     .setEmoji("CONTROL.BLOCKCROSS")
-            ],
-            ephemeral: true
+            ], ephemeral: true
         });
-    }
-    const status = channel.topic.split(" ")[1];
-    if (status === "Archived") {
-        await interaction.reply({
+    } else if (interaction.channel!.parent!.id !== ticketChannel) {
+        return await interaction.reply({
             embeds: [
                 new EmojiEmbed()
-                    .setTitle("Delete Ticket")
-                    .setDescription("Your ticket is being deleted...")
+                    .setTitle("Not a ticket")
+                    .setDescription("This channel isn't a ticket, so you can't delete it.")
                     .setStatus("Danger")
-                    .setEmoji("GUILD.TICKET.CLOSE")
-            ]
+                    .setEmoji("CONTROL.BLOCKCROSS")
+            ], ephemeral: true
         });
+    }
+    const channel: PrivateThreadChannel | TextChannel = interaction.channel as PrivateThreadChannel | TextChannel;
+    let status: string | null = ("topic" in interaction.channel) ? interaction.channel!.topic : interaction.channel.name;
+    status = status ?? "";
+    if (status.endsWith("Archived")) { status = "Archived"; }
+    else { status = "Active"; }
+
+    const uID = channel.type === Discord.ChannelType.PrivateThread ? channel.name.split(" - ")[1] : channel.topic!.split(" ")[0];
+
+    if (status === "Archived") {
+        // Delete the ticket
+
         const data = {
             meta: {
-                type: "ticketDeleted",
-                displayName: "Ticket Deleted",
+                type: "ticketClosed",
+                displayName: "Ticket Closed",
                 calculateType: "ticketUpdate",
                 color: NucleusColors.red,
                 emoji: "GUILD.TICKET.CLOSE",
@@ -52,85 +54,45 @@
             },
             list: {
                 ticketFor: entry(
-                    channel.topic.split(" ")[0],
-                    renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)
+                    uID!,
+                    renderUser((await interaction.guild.members.fetch(uID!)).user)
                 ),
-                deletedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)),
-                deleted: entry(new Date().getTime(), renderDelta(new Date().getTime()))
+                closedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as Discord.User)),
+                closed: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+                ticketChannel: entry(channel.id, channel.name)
             },
             hidden: {
                 guild: interaction.guild.id
             }
         };
         log(data);
-        interaction.channel.delete();
-        return;
+
+        await channel.delete();
     } else if (status === "Active") {
+        // Close the ticket
+
+        if (channel.isThread()) {
+            channel.setName(`${channel.name.replace("Active", "Archived")}`);
+            channel.members.remove(channel.name.split(" - ")[1]!);
+        } else {
+            channel.setTopic(`${(channel.topic ?? "").replace("Active", "Archived")}`);
+            if (!channel.topic!.includes("Archived")) { channel.setTopic("0 Archived"); }
+            await channel.permissionOverwrites.delete(channel.topic!.split(" ")[0]!);
+        }
+        preloadPage(interaction.channel.id, "privacy", "2")
         await interaction.reply({
             embeds: [
                 new EmojiEmbed()
-                    .setTitle("Close Ticket")
-                    .setDescription("Your ticket is being closed...")
-                    .setStatus("Warning")
-                    .setEmoji("GUILD.TICKET.ARCHIVED")
-            ]
-        });
-        const overwrites = [
-            {
-                id: channel.topic.split(" ")[0],
-                deny: ["VIEW_CHANNEL"],
-                type: "member"
-            },
-            {
-                id: interaction.guild.id,
-                deny: ["VIEW_CHANNEL"],
-                type: "role"
-            }
-        ] as Discord.OverwriteResolvable[];
-        if (config.tickets.supportRole !== null) {
-            overwrites.push({
-                id: interaction.guild.roles.cache.get(config.tickets.supportRole),
-                allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
-                type: "role"
-            });
-        }
-        channel.edit({ permissionOverwrites: overwrites });
-        channel.setTopic(`${channel.topic.split(" ")[0]} Archived`);
-        const data = {
-            meta: {
-                type: "ticketClosed",
-                displayName: "Ticket Closed",
-                calculateType: "ticketUpdate",
-                color: NucleusColors.yellow,
-                emoji: "GUILD.TICKET.ARCHIVED",
-                timestamp: new Date().getTime()
-            },
-            list: {
-                ticketFor: entry(
-                    channel.topic.split(" ")[0],
-                    renderUser((await interaction.guild.members.fetch(channel.topic.split(" ")[0])).user)
-                ),
-                closedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)),
-                closed: entry(new Date().getTime(), renderDelta(new Date().getTime())),
-                ticketChannel: entry(channel.id, renderChannel(channel))
-            },
-            hidden: {
-                guild: interaction.guild.id
-            }
-        };
-        log(data);
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Close Ticket")
-                    .setDescription(
-                        "This ticket has been closed.\nType `/ticket close` again to delete it.\n\nNote: Check `/privacy` for details about transcripts."
-                    )
+                    .setTitle("Archived Ticket")
+                    .setDescription(`This ticket has been Archived. Type ${await getCommandMentionByName("ticket/close")} to delete it.` +
+                        await client.database.premium.hasPremium(interaction.guild.id) ?
+                        `\n\nFor more info on transcripts, check ${await getCommandMentionByName("privacy")}` :
+                        "")
                     .setStatus("Warning")
                     .setEmoji("GUILD.TICKET.ARCHIVED")
             ],
             components: [
-                new ActionRowBuilder().addComponents(
+                new ActionRowBuilder<ButtonBuilder>().addComponents(
                     [
                         new ButtonBuilder()
                             .setLabel("Delete")
@@ -138,27 +100,52 @@
                             .setCustomId("closeticket")
                             .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
                     ].concat(
-                        client.database.premium.hasPremium(interaction.guild.id)
+                        await client.database.premium.hasPremium(interaction.guild.id)
                             ? [
-                                  new ButtonBuilder()
-                                      .setLabel("Create Transcript and Delete")
-                                      .setStyle(ButtonStyle.Primary)
-                                      .setCustomId("createtranscript")
-                                      .setEmoji(getEmojiByName("CONTROL.DOWNLOAD", "id"))
-                              ]
+                                    new ButtonBuilder()
+                                        .setLabel("Create Transcript and Delete")
+                                        .setStyle(ButtonStyle.Primary)
+                                        .setCustomId("createtranscript")
+                                        .setEmoji(getEmojiByName("CONTROL.DOWNLOAD", "id"))
+                                ]
                             : []
                     )
                 )
             ]
         });
-        return;
+        const data = {
+            meta: {
+                type: "ticketClosed",
+                displayName: "Ticket Archived",
+                calculateType: "ticketUpdate",
+                color: NucleusColors.yellow,
+                emoji: "GUILD.TICKET.ARCHIVED",
+                timestamp: new Date().getTime()
+            },
+            list: {
+                ticketFor: entry(
+                    uID!,
+                    renderUser((await interaction.guild.members.fetch(uID!)).user)
+                ),
+                archivedBy: entry(interaction.member!.user.id, renderUser(interaction.member!.user as Discord.User)),
+                archived: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+                ticketChannel: entry(channel.id, renderChannel(channel))
+            },
+            hidden: {
+                guild: interaction.guild.id
+            }
+        };
+        log(data);
     }
+    return;
 }
 
-async function purgeByUser(member, guild) {
+
+async function purgeByUser(member: string, guild: string) {
     const config = await client.database.guilds.read(guild.id);
+    const fetchedGuild = await client.guilds.fetch(guild);
     if (!config.tickets.category) return;
-    const tickets = guild.channels.cache.get(config.tickets.category);
+    const tickets = fetchedGuild.channels.cache.get(config.tickets.category);
     if (!tickets) return;
     const ticketChannels = tickets.children;
     let deleted = 0;
@@ -198,4 +185,4 @@
     }
 }
 
-export { purgeByUser };
+export { purgeByUser };
\ No newline at end of file
diff --git a/src/commands/help.ts b/src/commands/help.ts
index c9bba7d..767ca46 100644
--- a/src/commands/help.ts
+++ b/src/commands/help.ts
@@ -8,13 +8,13 @@
 const callback = async (interaction: CommandInteraction): Promise<void> => {
     interaction.reply({components: [new ActionRowBuilder<ButtonBuilder>().addComponents(
         new ButtonBuilder()
-            .setLabel("Verify")
+            .setLabel("Create ticket")
             .setStyle(ButtonStyle.Primary)
-            .setCustomId("verifybutton")
+            .setCustomId("createticket")
     )]}); // TODO: FINISH THIS FOR RELEASE
 };
 
-const check = (_interaction: CommandInteraction) => {
+const check = () => {
     return true;
 };
 
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;
 };
diff --git a/src/commands/nucleus/ping.ts b/src/commands/nucleus/ping.ts
index 3cbd049..12f1c6b 100644
--- a/src/commands/nucleus/ping.ts
+++ b/src/commands/nucleus/ping.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
 import type { CommandInteraction } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
diff --git a/src/commands/nucleus/premium.ts b/src/commands/nucleus/premium.ts
index 9bbc36e..745f167 100644
--- a/src/commands/nucleus/premium.ts
+++ b/src/commands/nucleus/premium.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 EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
diff --git a/src/commands/nucleus/suggest.ts b/src/commands/nucleus/suggest.ts
index e31696b..de0e69b 100644
--- a/src/commands/nucleus/suggest.ts
+++ b/src/commands/nucleus/suggest.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from './../../utils/defaultEmbeds.js';
+import { LoadingEmbed } from '../../utils/defaults.js';
 import { ButtonStyle, CommandInteraction } from "discord.js";
 import Discord from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
@@ -29,56 +29,44 @@
         )
         .setColor("Danger")
         .setInverted(true)
+        .setFailedMessage("Your suggestion was deleted", "Success", "ICONS.ADD")
         .send(true);
-    if (confirmation.cancelled) return;
-    if (confirmation.success) {
-        await (client.channels.cache.get("955161206459600976") as Discord.TextChannel).send({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Suggestion")
-                    .setDescription(
-                        `**From:** ${renderUser(interaction.member!.user as Discord.User)}\n**Suggestion:**\n> ${suggestion}\n\n` +
-                        `**Server:** ${interaction.guild!.name} (${interaction.guild!.id})\n`,
-                    )
-                    .setStatus("Warning")
-            ], components: [new Discord.ActionRowBuilder<Discord.ButtonBuilder>().addComponents(
-                new Discord.ButtonBuilder()
-                    .setCustomId("suggestionAccept")
-                    .setLabel("Accept")
-                    .setStyle(ButtonStyle.Secondary)
-                    .setEmoji(getEmojiByName("ICONS.ADD", "id")),
-                new Discord.ButtonBuilder()
-                    .setCustomId("suggestionDeny")
-                    .setLabel("Delete")
-                    .setStyle(ButtonStyle.Secondary)
-                    .setEmoji(getEmojiByName("ICONS.REMOVE", "id"))
-            )]
-        });
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setEmoji("ICONS.ADD")
-                    .setTitle("Suggest")
-                    .setDescription("Your suggestion was sent successfully")
-                    .setStatus("Success")
-            ],
-            components: []
-        });
-    } else {
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setEmoji("ICONS.OPP.ADD")
-                    .setTitle("Suggest")
-                    .setDescription("No changes were made")
-                    .setStatus("Danger")
-            ],
-            components: []
-        });
-    }
+    if (confirmation.cancelled || !confirmation.success) return;
+    await (client.channels.cache.get("955161206459600976") as Discord.TextChannel).send({
+        embeds: [
+            new EmojiEmbed()
+                .setTitle("Suggestion")
+                .setDescription(
+                    `**From:** ${renderUser(interaction.member!.user as Discord.User)}\n**Suggestion:**\n> ${suggestion}\n\n` +
+                    `**Server:** ${interaction.guild!.name} (${interaction.guild!.id})\n`,
+                )
+                .setStatus("Warning")
+        ], components: [new Discord.ActionRowBuilder<Discord.ButtonBuilder>().addComponents(
+            new Discord.ButtonBuilder()
+                .setCustomId("suggestionAccept")
+                .setLabel("Accept")
+                .setStyle(ButtonStyle.Secondary)
+                .setEmoji(getEmojiByName("ICONS.ADD", "id")),
+            new Discord.ButtonBuilder()
+                .setCustomId("suggestionDeny")
+                .setLabel("Delete")
+                .setStyle(ButtonStyle.Secondary)
+                .setEmoji(getEmojiByName("ICONS.REMOVE", "id"))
+        )]
+    });
+    await interaction.editReply({
+        embeds: [
+            new EmojiEmbed()
+                .setEmoji("ICONS.ADD")
+                .setTitle("Suggest")
+                .setDescription("Your suggestion was sent successfully")
+                .setStatus("Success")
+        ],
+        components: []
+    });
 };
 
-const check = (_interaction: CommandInteraction) => {
+const check = () => {
     return true;
 };
 
diff --git a/src/commands/privacy.ts b/src/commands/privacy.ts
index a427688..9100302 100644
--- a/src/commands/privacy.ts
+++ b/src/commands/privacy.ts
@@ -1,43 +1,17 @@
-import { LoadingEmbed } from "./../utils/defaultEmbeds.js";
-import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
+import { LoadingEmbed } from "../utils/defaults.js";
+import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuOptionBuilder, SelectMenuOptionBuilder, StringSelectMenuBuilder } from "discord.js";
 import { SlashCommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../utils/getEmojiByName.js";
 import createPageIndicator from "../utils/createPageIndicator.js";
 import client from "../utils/client.js";
 import confirmationMessage from "../utils/confirmationMessage.js";
+import { Embed } from "../utils/defaults.js";
 
 const command = new SlashCommandBuilder()
     .setName("privacy")
     .setDescription("Information and options for you and your server's settings");
 
-class Embed {
-    embed: Discord.EmbedBuilder;
-    title: string;
-    description = "";
-    pageId = 0;
-    components?: ActionRowBuilder[] = [];
-    setEmbed(embed: Discord.EmbedBuilder) {
-        this.embed = embed;
-        return this;
-    }
-    setTitle(title: string) {
-        this.title = title;
-        return this;
-    }
-    setDescription(description: string) {
-        this.description = description;
-        return this;
-    }
-    setPageId(pageId: number) {
-        this.pageId = pageId;
-        return this;
-    }
-    setComponents(components: ActionRowBuilder[]) {
-        this.components = components;
-        return this;
-    }
-}
 
 const callback = async (interaction: CommandInteraction): Promise<void> => {
     const pages = [
@@ -78,7 +52,7 @@
                     .setDescription(
                         "**Facebook** - Facebook trackers include data such as your date of birth, and guess your age if not entered, your preferences, who you interact with and more.\n" +
                             "**AMP** - AMP is a technology that allows websites to be served by Google. This means Google can store and track data, and are pushing this to as many pages as possible.\n\n" +
-                            "Transcripts allow you to store all messages sent in a channel. This could be an issue in some cases, as they are hosted on [Pastebin](https://pastebin.com), so a leaked link could show all messages sent in the channel.\n"
+                            "Transcripts allow you to store all messages sent in a channel. This could be an issue in some cases, as they are hosted on [Pastebin](https://pastebin.com), so a leaked link could show all messages sent in the channel.\n"  // TODO: Not on pastebin
                     )
                     .setEmoji("NUCLEUS.LOGO")
                     .setStatus("Danger")
@@ -87,7 +61,7 @@
             .setDescription("Regarding Facebook and AMP filter types, and ticket transcripts")
             .setPageId(2)
     ].concat(
-        (interaction.member as Discord.GuildMember).permissions.has("ADMINISTRATOR")
+        (interaction.member as Discord.GuildMember).permissions.has("Administrator")
             ? [
                   new Embed()
                       .setEmbed(
@@ -101,7 +75,7 @@
                       .setDescription("Options")
                       .setPageId(3)
                       .setComponents([
-                          new ActionRowBuilder().addComponents([
+                          new ActionRowBuilder<ButtonBuilder>().addComponents([
                               new ButtonBuilder()
                                   .setLabel("Clear all data")
                                   .setCustomId("clear-all-data")
@@ -116,20 +90,20 @@
         fetchReply: true,
         ephemeral: true
     });
-    let page = 0;
+    let page = parseInt(client.preloadPage[interaction.channel!.id] ? client.preloadPage[interaction.channel!.id]?.argument! : "0");
 
     let selectPaneOpen = false;
     let nextFooter = null;
 
     let timedOut = false;
     while (!timedOut) {
-        let selectPane = [];
+        let selectPane: Discord.ActionRowBuilder<ButtonBuilder | StringSelectMenuBuilder>[] = [];
 
         if (selectPaneOpen) {
-            const options = [];
+            const options: SelectMenuOptionBuilder[] = [];
             pages.forEach((embed) => {
                 options.push(
-                    new SelectMenuOption({
+                    new StringSelectMenuOptionBuilder({
                         label: embed.title,
                         value: embed.pageId.toString(),
                         description: embed.description || ""
@@ -137,8 +111,8 @@
                 );
             });
             selectPane = [
-                new ActionRowBuilder().addComponents([
-                    new Discord.SelectMenuBuilder()
+                new ActionRowBuilder<StringSelectMenuBuilder>().addComponents([
+                    new Discord.StringSelectMenuBuilder()
                         .addOptions(options)
                         .setCustomId("page")
                         .setMaxValues(1)
@@ -146,8 +120,8 @@
                 ])
             ];
         }
-        const components = selectPane.concat([
-            new ActionRowBuilder().addComponents([
+        const components: ActionRowBuilder<ButtonBuilder | StringSelectMenuBuilder>[] = selectPane.concat([
+            new ActionRowBuilder<ButtonBuilder>().addComponents(
                 new ButtonBuilder()
                     .setCustomId("left")
                     .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
@@ -163,36 +137,39 @@
                     .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
                     .setStyle(ButtonStyle.Secondary)
                     .setDisabled(page === pages.length - 1)
-            ])
+            )
         ]);
-        const em = new Discord.EmbedBuilder(pages[page].embed);
-        em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
-        em.setFooter({ text: nextFooter ?? "" });
+        const em = new Discord.EmbedBuilder(pages[page]!.embed);
+        em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
+        if (nextFooter) em.setFooter({ text: nextFooter });
         await interaction.editReply({
             embeds: [em],
-            components: components.concat(pages[page].components)
+            components: components.concat(pages[page]?.componentsToSet ?? [])
         });
         let i;
         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;
         }
         nextFooter = null;
         i.deferUpdate();
-        if (i.component.customId === "left") {
+        if (i.customId === "left") {
             if (page > 0) page--;
             selectPaneOpen = false;
-        } else if (i.component.customId === "right") {
+        } else if (i.customId === "right") {
             if (page < pages.length - 1) page++;
             selectPaneOpen = false;
-        } else if (i.component.customId === "select") {
+        } else if (i.customId === "select") {
             selectPaneOpen = !selectPaneOpen;
-        } else if (i.component.customId === "page") {
-            page = parseInt(i.values[0]);
+        } else if (i.customId === "page" && i.isStringSelectMenu()) {
+            page = parseInt(i.values[0]!);
             selectPaneOpen = false;
-        } else if (i.component.customId === "clear-all-data") {
+        } else if (i.customId === "clear-all-data") {
             const confirmation = await new confirmationMessage(interaction)
                 .setEmoji("CONTROL.BLOCKCROSS")
                 .setTitle("Clear All Data")
@@ -206,8 +183,8 @@
                 break;
             }
             if (confirmation.success) {
-                client.database.guilds.delete(interaction.guild.id);
-                client.database.history.delete(interaction.guild.id);
+                client.database.guilds.delete(interaction.guild!.id);
+                client.database.history.delete(interaction.guild!.id);
                 nextFooter = "All data cleared";
                 continue;
             } else {
@@ -215,15 +192,15 @@
                 continue;
             }
         } else {
-            const em = new Discord.EmbedBuilder(pages[page].embed);
-            em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
+            const em = new Discord.EmbedBuilder(pages[page]!.embed);
+            em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
             em.setFooter({ text: "Message closed" });
             interaction.editReply({ embeds: [em], components: [] });
             return;
         }
     }
-    const em = new Discord.EmbedBuilder(pages[page].embed);
-    em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
+    const em = new Discord.EmbedBuilder(pages[page]!.embed);
+    em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
     em.setFooter({ text: "Message timed out" });
     await interaction.editReply({
         embeds: [em],
@@ -231,7 +208,7 @@
     });
 };
 
-const check = (_interaction: CommandInteraction) => {
+const check = () => {
     return true;
 };
 
diff --git a/src/commands/role/user.ts b/src/commands/role/user.ts
index ac94b47..ad29811 100644
--- a/src/commands/role/user.ts
+++ b/src/commands/role/user.ts
@@ -1,5 +1,5 @@
-import { CommandInteraction, GuildMember, Role } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import type { CommandInteraction, GuildMember, Role, User } from "discord.js";
+import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import client from "../../utils/client.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
@@ -28,79 +28,68 @@
 
 const callback = async (interaction: CommandInteraction): Promise<unknown> => {
     const { renderUser, renderRole } = client.logger;
-    const action = interaction.options.getString("action");
+    const action = interaction.options.get("action")?.value as string;
+    const role: Role = (await interaction.guild!.roles.fetch(interaction.options.get("role")?.value as string))!;
     // TODO:[Modals] Replace this with a modal
     const confirmation = await new confirmationMessage(interaction)
         .setEmoji("GUILD.ROLES.DELETE")
         .setTitle("Role")
         .setDescription(
             keyValueList({
-                user: renderUser(interaction.options.getUser("user")),
-                role: renderRole(interaction.options.get("role"))
+                user: renderUser(interaction.options.getUser("user")! as User),
+                role: renderRole(role)
             }) +
                 `\nAre you sure you want to ${
                     action === "give" ? "give the role to" : "remove the role from"
                 } ${interaction.options.getUser("user")}?`
         )
         .setColor("Danger")
+        .setFailedMessage("No changes were made", "Success", "GUILD.ROLES.CREATE")
         .send();
-    if (confirmation.cancelled) return;
-    if (confirmation.success) {
-        try {
-            const member = interaction.options.getMember("user") as GuildMember;
-            const role = interaction.options.get("role") as unknown as Role;
-            if (interaction.options.getString("action") === "give") {
-                member.roles.add(role);
-            } else {
-                member.roles.remove(role);
-            }
-        } catch (e) {
-            return await interaction.editReply({
-                embeds: [
-                    new EmojiEmbed()
-                        .setTitle("Role")
-                        .setDescription("Something went wrong and the role could not be added")
-                        .setStatus("Danger")
-                        .setEmoji("CONTROL.BLOCKCROSS")
-                ],
-                components: []
-            });
+    if (confirmation.cancelled || !confirmation.success) return;
+    try {
+        const member = interaction.options.getMember("user") as GuildMember;
+        if ((interaction.options.get("action")?.value as string) === "give") {
+            member.roles.add(role);
+        } else {
+            member.roles.remove(role);
         }
+    } catch (e) {
         return await interaction.editReply({
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Role")
-                    .setDescription(`The role has been ${action === "give" ? "given" : "removed"} successfully`)
-                    .setStatus("Success")
-                    .setEmoji("GUILD.ROLES.CREATE")
-            ],
-            components: []
-        });
-    } else {
-        await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setEmoji("GUILD.ROLES.CREATE")
-                    .setTitle("Role")
-                    .setDescription("No changes were made.")
+                    .setDescription("Something went wrong and the role could not be added")
                     .setStatus("Danger")
+                    .setEmoji("CONTROL.BLOCKCROSS")
             ],
             components: []
         });
     }
+    return await interaction.editReply({
+        embeds: [
+            new EmojiEmbed()
+                .setTitle("Role")
+                .setDescription(`The role has been ${action === "give" ? "given" : "removed"} successfully`)
+                .setStatus("Success")
+                .setEmoji("GUILD.ROLES.CREATE")
+        ],
+        components: []
+    });
 };
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as GuildMember;
-    const me = interaction.guild.me!;
+    if (!interaction.guild) return
+    const me = interaction.guild.members.me!;
     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";
     // Check if Nucleus has permission to role
-    if (!me.permissions.has("MANAGE_ROLES")) throw new Error("I do not have the *Manage Roles* permission");
+    if (!me.permissions.has("ManageRoles")) return "I do not have the *Manage Roles* permission";
     // Allow the owner to role anyone
     if (member.id === interaction.guild.ownerId) return true;
     // Check if the user has manage_roles permission
-    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";
     // Allow role
     return true;
 };
diff --git a/src/commands/rolemenu.ts b/src/commands/rolemenu.ts
index 9aad543..c1ceb2e 100644
--- a/src/commands/rolemenu.ts
+++ b/src/commands/rolemenu.ts
@@ -10,7 +10,7 @@
     await roleMenu(interaction);
 };
 
-const check = (_interaction: CommandInteraction) => {
+const check = () => {
     return true;
 };
 
diff --git a/src/commands/server/about.ts b/src/commands/server/about.ts
index e5bea60..23a53b7 100644
--- a/src/commands/server/about.ts
+++ b/src/commands/server/about.ts
@@ -74,7 +74,7 @@
     });
 };
 
-const check = (_interaction: CommandInteraction) => {
+const check = () => {
     return true;
 };
 
diff --git a/src/commands/settings/commands.ts b/src/commands/settings/commands.ts
index 4493f79..34a197b 100644
--- a/src/commands/settings/commands.ts
+++ b/src/commands/settings/commands.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
 import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, TextInputComponent, Role, ButtonStyle } from "discord.js";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
@@ -108,7 +108,10 @@
         });
         let i;
         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;
@@ -209,8 +212,8 @@
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("MANAGE_GUILD"))
-        throw new Error("You must have the *Manage Server* permission to use this command");
+    if (!member.permissions.has("ManageGuild"))
+        return "You must have the *Manage Server* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/filters.ts b/src/commands/settings/filters.ts
index 1a297ca..f0291b9 100644
--- a/src/commands/settings/filters.ts
+++ b/src/commands/settings/filters.ts
@@ -10,8 +10,8 @@
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("MANAGE_MESSAGES"))
-        throw new Error("You must have the *Manage Messages* permission to use this command");
+    if (!member.permissions.has("ManageMessages"))
+        return "You must have the *Manage Messages* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/logs/attachment.ts b/src/commands/settings/logs/attachment.ts
index 7d4fef3..326246a 100644
--- a/src/commands/settings/logs/attachment.ts
+++ b/src/commands/settings/logs/attachment.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../../utils/defaults.js";
 import { ChannelType } from "discord-api-types/v9";
 import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
 import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
@@ -147,7 +147,10 @@
         });
         let i;
         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;
@@ -190,8 +193,8 @@
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("MANAGE_GUILD"))
-        throw new Error("You must have the *Manage Server* permission to use this command");
+    if (!member.permissions.has("ManageGuild"))
+        return "You must have the *Manage Server* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/logs/channel.ts b/src/commands/settings/logs/channel.ts
index 0288bf7..9129841 100644
--- a/src/commands/settings/logs/channel.ts
+++ b/src/commands/settings/logs/channel.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../../utils/defaults.js";
 import { ChannelType } from "discord-api-types/v9";
 import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
 import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
@@ -140,7 +140,10 @@
         });
         let i;
         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;
         }
@@ -182,8 +185,8 @@
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("MANAGE_GUILD"))
-        throw new Error("You must have the *Manage Server* permission to use this command");
+    if (!member.permissions.has("ManageGuild"))
+        return "You must have the *Manage Server* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/logs/events.ts b/src/commands/settings/logs/events.ts
index 9eaf25c..ae04e89 100644
--- a/src/commands/settings/logs/events.ts
+++ b/src/commands/settings/logs/events.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../../utils/defaults.js";
 import Discord, { CommandInteraction, Message, ActionRowBuilder, ButtonBuilder, SelectMenuBuilder, ButtonStyle } from "discord.js";
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
@@ -75,7 +75,10 @@
         })) as Message;
         let i;
         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;
@@ -105,8 +108,8 @@
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("MANAGE_GUILD"))
-        throw new Error("You must have the *Manage Server* permission to use this command");
+    if (!member.permissions.has("ManageGuild"))
+        return "You must have the *Manage Server* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/logs/staff.ts b/src/commands/settings/logs/staff.ts
index c1b2380..5a23839 100644
--- a/src/commands/settings/logs/staff.ts
+++ b/src/commands/settings/logs/staff.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../../utils/defaults.js";
 import { ChannelType } from "discord-api-types/v9";
 import Discord, { CommandInteraction, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
 import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
@@ -144,7 +144,10 @@
         });
         let i;
         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;
@@ -187,8 +190,8 @@
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("MANAGE_GUILD"))
-        throw new Error("You must have the *Manage Server* permission to use this command");
+    if (!member.permissions.has("ManageGuild"))
+        return "You must have the *Manage Server* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
index 02ab93e..e05485b 100644
--- a/src/commands/settings/rolemenu.ts
+++ b/src/commands/settings/rolemenu.ts
@@ -14,8 +14,8 @@
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("MANAGE_ROLES"))
-        throw Error("You must have the *Manage Roles* permission to use this command");
+    if (!member.permissions.has("ManageRoles"))
+        return "You must have the *Manage Roles* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/stats.ts b/src/commands/settings/stats.ts
index a768cb8..0e4c50b 100644
--- a/src/commands/settings/stats.ts
+++ b/src/commands/settings/stats.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
 import Discord, { CommandInteraction, Message, ActionRowBuilder, SelectMenuBuilder } from "discord.js";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
@@ -196,7 +196,10 @@
         });
         let i;
         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;
@@ -219,8 +222,8 @@
 
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("MANAGE_CHANNELS"))
-        throw new Error("You must have the *Manage Channels* permission to use this command");
+    if (!member.permissions.has("manageChannels"))
+        return "You must have the *Manage Channels* permission to use this command";
     return true;
 };
 
@@ -237,3 +240,4 @@
 export { command };
 export { callback };
 export { check };
+export { autocomplete };
\ No newline at end of file
diff --git a/src/commands/settings/tickets.ts b/src/commands/settings/tickets.ts
index 70ba52d..ee0f2d1 100644
--- a/src/commands/settings/tickets.ts
+++ b/src/commands/settings/tickets.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
@@ -276,7 +276,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;
@@ -376,7 +379,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) {
                     innerTimedOut = true;
                     continue;
@@ -627,7 +633,10 @@
         }
         let i;
         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;
@@ -734,7 +743,7 @@
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
     if (!member.permissions.has("ManageGuild"))
-        throw new Error("You must have the *Manage Server* permission to use this command");
+        return "You must have the *Manage Server* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/verify.ts b/src/commands/settings/verify.ts
index cceadae..a8b0ae0 100644
--- a/src/commands/settings/verify.ts
+++ b/src/commands/settings/verify.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
 import Discord, {
     CommandInteraction,
     Interaction,
@@ -157,7 +157,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) {
             timedOut = true;
             continue;
@@ -243,7 +246,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) {
                     innerTimedOut = true;
                     continue;
@@ -381,7 +387,7 @@
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
     if (!member.permissions.has("ManageGuild"))
-        throw new Error("You must have the *Manage Server* permission to use this command");
+        return "You must have the *Manage Server* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/settings/welcome.ts b/src/commands/settings/welcome.ts
index 7f02cd7..9892638 100644
--- a/src/commands/settings/welcome.ts
+++ b/src/commands/settings/welcome.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
 import Discord, {
     Channel,
     CommandInteraction,
@@ -240,7 +240,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;
@@ -298,7 +301,7 @@
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
     if (!member.permissions.has("ManageGuild"))
-        throw new Error("You must have the *Manage Server* permission to use this command");
+        return "You must have the *Manage Server* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/tags/create.ts b/src/commands/tags/create.ts
index 5379bf8..788902e 100644
--- a/src/commands/tags/create.ts
+++ b/src/commands/tags/create.ts
@@ -64,7 +64,7 @@
             ephemeral: true
         });
     const confirmation = await new confirmationMessage(interaction)
-        .setEmoji("PUNISH.NICKNAME.YELLOW", "PUNISH.NICKNAME.RED")
+        .setEmoji("PUNISH.NICKNAME.YELLOW")
         .setTitle("Tag create")
         .setDescription(
             keyValueList({
@@ -74,18 +74,9 @@
         )
         .setColor("Warning")
         .setInverted(true)
+        .setFailedMessage("No changes were made", "Success", "PUNISH.NICKNAME.GREEN")
         .send();
-    if (confirmation.cancelled) return;
-    if (!confirmation.success)
-        return await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Tag Create")
-                    .setDescription("No changes were made")
-                    .setStatus("Success")
-                    .setEmoji("PUNISH.NICKNAME.GREEN")
-            ]
-        });
+    if (confirmation.cancelled || !confirmation.success) return;
     try {
         await client.database.guilds.write(interaction.guild!.id, {
             [`tags.${name}`]: value
@@ -118,7 +109,7 @@
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
     if (!member.permissions.has("ManageMessages"))
-        throw new Error("You must have the *Manage Messages* permission to use this command");
+        return "You must have the *Manage Messages* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/tags/delete.ts b/src/commands/tags/delete.ts
index 6d76eb1..18143d3 100644
--- a/src/commands/tags/delete.ts
+++ b/src/commands/tags/delete.ts
@@ -27,7 +27,7 @@
             ephemeral: true
         });
     const confirmation = await new confirmationMessage(interaction)
-        .setEmoji("PUNISH.NICKNAME.YELLOW", "PUNISH.NICKNAME.RED")
+        .setEmoji("PUNISH.NICKNAME.YELLOW")
         .setTitle("Tag Delete")
         .setDescription(
             keyValueList({
@@ -37,18 +37,9 @@
         )
         .setColor("Warning")
         .setInverted(true)
+        .setFailedMessage("No changes were made", "Success", "PUNISH.NICKNAME.GREEN")
         .send();
-    if (confirmation.cancelled) return;
-    if (!confirmation.success)
-        return await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Tag Delete")
-                    .setDescription("No changes were made")
-                    .setStatus("Success")
-                    .setEmoji("PUNISH.NICKNAME.GREEN")
-            ]
-        });
+    if (confirmation.cancelled || !confirmation.success) return;
     try {
         await client.database.guilds.write(interaction.guild!.id, null, ["tags." + name]);
         await client.memory.forceUpdate(interaction.guild!.id);
@@ -80,7 +71,7 @@
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as Discord.GuildMember;
     if (!member.permissions.has("ManageMessages"))
-        throw new Error("You must have the *Manage Messages* permission to use this command");
+        return "You must have the *Manage Messages* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/tags/edit.ts b/src/commands/tags/edit.ts
index 018a0bb..e15f9ac 100644
--- a/src/commands/tags/edit.ts
+++ b/src/commands/tags/edit.ts
@@ -19,9 +19,9 @@
 
 const callback = async (interaction: CommandInteraction): Promise<unknown> => {
     if (!interaction.guild) return;
-    const name = interaction.options.getString("name");
-    const value = interaction.options.getString("value") ?? "";
-    const newname = interaction.options.getString("newname") ?? "";
+    const name = interaction.options.get("name")?.value as string;
+    const value = interaction.options.get("value")?.value as string;
+    const newname = interaction.options.get("newname")?.value as string;
     if (!newname && !value)
         return await interaction.reply({
             embeds: [
@@ -79,7 +79,7 @@
             ephemeral: true
         });
     const confirmation = await new confirmationMessage(interaction)
-        .setEmoji("PUNISH.NICKNAME.YELLOW", "PUNISH.NICKNAME.RED")
+        .setEmoji("PUNISH.NICKNAME.YELLOW")
         .setTitle("Tag Edit")
         .setDescription(
             keyValueList({
@@ -89,27 +89,18 @@
         )
         .setColor("Warning")
         .setInverted(true)
+        .setFailedMessage("No changes were made", "Success", "PUNISH.NICKNAME.GREEN")
         .send();
     if (confirmation.cancelled) return;
-    if (!confirmation.success)
-        return await interaction.editReply({
-            embeds: [
-                new EmojiEmbed()
-                    .setTitle("Tag Edit")
-                    .setDescription("No changes were made")
-                    .setStatus("Success")
-                    .setEmoji("PUNISH.NICKNAME.GREEN")
-            ]
-        });
     try {
         const toSet: Record<string, string> = {};
         const toUnset: string[] = [];
         if (value) toSet[`tags.${name}`] = value;
         if (newname) {
             toUnset.push(`tags.${name}`);
-            toSet[`tags.${newname}`] = data.tags[name];
+            toSet[`tags.${newname}`] = data.tags[name]!;
         }
-        await client.database.guilds.write(interaction.guild.id, toSet === {} ? null : toSet, toUnset);
+        await client.database.guilds.write(interaction.guild.id, Object.keys(toSet).length === 0 ? null : toSet, toUnset);
         await client.memory.forceUpdate(interaction.guild!.id);
     } catch (e) {
         return await interaction.editReply({
@@ -138,7 +129,7 @@
 const check = (interaction: CommandInteraction) => {
     const member = interaction.member as GuildMember;
     if (!member.permissions.has("ManageMessages"))
-        throw new Error("You must have the *Manage Messages* permission to use this command");
+        return "You must have the *Manage Messages* permission to use this command";
     return true;
 };
 
diff --git a/src/commands/tags/list.ts b/src/commands/tags/list.ts
index aee4c71..f0563c7 100644
--- a/src/commands/tags/list.ts
+++ b/src/commands/tags/list.ts
@@ -1,21 +1,22 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
 import Discord, {
     CommandInteraction,
     Message,
     ActionRowBuilder,
-    Component,
     ButtonBuilder,
     MessageComponentInteraction,
     EmbedBuilder,
-    SelectMenuInteraction,
-    MessageSelectOptionData,
-    ButtonStyle
+    ButtonStyle,
+    ButtonComponent,
+    StringSelectMenuBuilder
 } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import client from "../../utils/client.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
 import createPageIndicator from "../../utils/createPageIndicator.js";
+interface MessageSelectOptionData { label: string; value: string; description?: string; }
+
 
 class Embed {
     embed: Discord.EmbedBuilder = new EmbedBuilder();
@@ -45,9 +46,9 @@
 
 const callback = async (interaction: CommandInteraction): Promise<void> => {
     const data = await client.database.guilds.read(interaction.guild!.id);
-    const tags = data.getKey("tags");
+    const tags = data.tags;
     let strings = [];
-    if (data === {}) strings = ["*No tags exist*"];
+    if (Object.keys(tags).length === 0) strings = ["*No tags exist*"];
     else {
         let string = "";
         for (const tag in tags) {
@@ -86,8 +87,7 @@
     let cancelled = false;
     let timedOut = false;
     while (!cancelled && !timedOut) {
-        let selectPane: ActionRowBuilder[] = [];
-
+        let selectPane: ActionRowBuilder<ButtonBuilder | StringSelectMenuBuilder>[] = [];
         if (selectPaneOpen) {
             const options: MessageSelectOptionData[] = [];
             pages.forEach((embed) => {
@@ -98,8 +98,8 @@
                 });
             });
             selectPane = [
-                new ActionRowBuilder().addComponents([
-                    new Discord.SelectMenuBuilder()
+                new ActionRowBuilder<StringSelectMenuBuilder>().addComponents([
+                    new Discord.StringSelectMenuBuilder()
                         .addOptions(options)
                         .setCustomId("page")
                         .setMaxValues(1)
@@ -107,12 +107,12 @@
                 ])
             ];
         }
-        const em = new Discord.EmbedBuilder(pages[page]!.embed);
-        em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
+        const em = new Discord.EmbedBuilder(pages[page]!.embed.data);
+        em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
         await interaction.editReply({
             embeds: [em],
             components: selectPane.concat([
-                new ActionRowBuilder().addComponents([
+                new ActionRowBuilder<ButtonBuilder>().addComponents([
                     new ButtonBuilder()
                         .setCustomId("left")
                         .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
@@ -137,32 +137,35 @@
         });
         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;
         }
         i.deferUpdate();
-        if ((i.component as Component).customId === "left") {
+        if ((i.component as ButtonComponent).customId === "left") {
             if (page > 0) page--;
             selectPaneOpen = false;
-        } else if ((i.component as Component).customId === "right") {
+        } else if ((i.component as ButtonComponent).customId === "right") {
             if (page < pages.length - 1) page++;
             selectPaneOpen = false;
-        } else if ((i.component as Component).customId === "select") {
+        } else if (i.customId === "select") {
             selectPaneOpen = !selectPaneOpen;
-        } else if ((i.component as Component).customId === "page") {
-            page = parseInt((i as SelectMenuInteraction).values[0]!);
+        } else if (i.customId === "page" && i.isStringSelectMenu()) {
+            page = parseInt(i.values[0]!);
             selectPaneOpen = false;
         } else {
             cancelled = true;
         }
     }
-    const em = new Discord.EmbedBuilder(pages[page]!.embed);
+    const em = new Discord.EmbedBuilder(pages[page]!.embed.data);
     if (timedOut) {
-        em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page) + " | Message timed out");
+        em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page) + " | Message timed out");
     } else {
-        em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page) + " | Message closed");
+        em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page) + " | Message closed");
     }
     await interaction.editReply({
         embeds: [em],
diff --git a/src/commands/user/about.ts b/src/commands/user/about.ts
index aa45690..e43ecb7 100644
--- a/src/commands/user/about.ts
+++ b/src/commands/user/about.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed, Embed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed, Embed } from "../../utils/defaults.js";
 import Discord, {
     CommandInteraction,
     GuildMember,
@@ -256,7 +256,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 {
             timedOut = true;
             continue;
diff --git a/src/commands/user/avatar.ts b/src/commands/user/avatar.ts
index 5980072..88b3270 100644
--- a/src/commands/user/avatar.ts
+++ b/src/commands/user/avatar.ts
@@ -35,7 +35,7 @@
     });
 };
 
-const check = (_interaction: CommandInteraction) => {
+const check = () => {
     return true;
 };
 
diff --git a/src/commands/user/track.ts b/src/commands/user/track.ts
index 06f498a..0ab5c10 100644
--- a/src/commands/user/track.ts
+++ b/src/commands/user/track.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
 import Discord, { CommandInteraction, GuildMember, Message, ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
@@ -166,7 +166,10 @@
         })) as Message;
         let component;
         try {
-            component = await m.awaitMessageComponent({ time: 300000 });
+            component = 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;
diff --git a/src/commands/verify.ts b/src/commands/verify.ts
index b9556a6..4fafe69 100644
--- a/src/commands/verify.ts
+++ b/src/commands/verify.ts
@@ -8,7 +8,7 @@
     verify(interaction);
 };
 
-const check = (_interaction: CommandInteraction) => {
+const check = () => {
     return true;
 };
 
diff --git a/src/config/emojis.json b/src/config/emojis.json
index cbf3dc3..4bdadee 100644
--- a/src/config/emojis.json
+++ b/src/config/emojis.json
@@ -42,7 +42,8 @@
             "THREAD_CHANNEL": "990210005108158514",
             "THREAD_PIPE": "990213168183779348",
             "RULES": "990213153080115250",
-            "FORUM": "1061706437526552716"
+            "FORUM": "1061706437526552716",
+            "CATEGORY": "1064943289708597348"
         }
     },
     "CONTROL": {
diff --git a/src/context/messages/purgeto.ts b/src/context/messages/purgeto.ts
index e2ec6e4..df52e0b 100644
--- a/src/context/messages/purgeto.ts
+++ b/src/context/messages/purgeto.ts
@@ -1,9 +1,10 @@
 import confirmationMessage from '../../utils/confirmationMessage.js';
 import EmojiEmbed from '../../utils/generateEmojiEmbed.js';
-import { LoadingEmbed } from './../../utils/defaultEmbeds.js';
+import { LoadingEmbed } from '../../utils/defaults.js';
 import Discord, { ActionRowBuilder, ButtonBuilder, ButtonStyle, ContextMenuCommandBuilder, GuildTextBasedChannel, MessageContextMenuCommandInteraction } from "discord.js";
 import client from "../../utils/client.js";
 import getEmojiByName from '../../utils/getEmojiByName.js';
+import { JSONTranscriptFromMessageArray, JSONTranscriptToHumanReadable } from "../../utils/logTranscripts.js";
 
 const command = new ContextMenuCommandBuilder()
     .setName("Purge up to here")
@@ -12,7 +13,7 @@
 async function waitForButton(m: Discord.Message, member: Discord.GuildMember): Promise<boolean> {
     let component;
     try {
-        component = m.awaitMessageComponent({ time: 200000, filter: (i) => i.user.id === member.id });
+        component = m.awaitMessageComponent({ time: 200000, filter: (i) => i.user.id === member.id && i.channel!.id === m.channel.id });
     } catch (e) {
         return false;
     }
@@ -120,6 +121,7 @@
             )
             .setColor("Danger")
             .addReasonButton(reason ?? "")
+            .setFailedMessage("No changes were made", "Success", "CHANNEL.PURGE.GREEN")
             .send(true)
         reason = reason ?? ""
         if (confirmation.cancelled) timedOut = true;
@@ -130,16 +132,7 @@
             deleteUser = confirmation.components["onlySelectedUser"]!.active;
         }
     } while (!chosen && !timedOut);
-    if (timedOut) return;
-    if (!confirmation.success) {
-        await interaction.editReply({ embeds: [new EmojiEmbed()
-            .setTitle("Purge")
-            .setDescription("No changes were made")
-            .setEmoji("CHANNEL.PURGE.GREEN")
-            .setStatus("Success")
-        ], components: [] });
-        return;
-    }
+    if (timedOut || !confirmation.success) return;
     const filteredMessages = history
         .filter(m => m.createdTimestamp >= allowedMessage!.createdTimestamp)  // older than selected
         .filter(m => deleteUser ? m.author.id === targetMember.id : true)  // only selected user
@@ -191,31 +184,9 @@
         }
     };
     log(data);
-    let out = "";
-    deleted.reverse().forEach((message) => {
-        if (!message) {
-            out += "Unknown message\n\n"
-        } else {
-            const author = message.author ?? { username: "Unknown", discriminator: "0000", id: "Unknown" };
-            out += `${author.username}#${author.discriminator} (${author.id}) [${new Date(
-                message.createdTimestamp
-            ).toISOString()}]\n`;
-            if (message.content) {
-                const lines = message.content.split("\n");
-                lines.forEach((line) => {
-                    out += `> ${line}\n`;
-                });
-            }
-            if (message.attachments.size > 0) {
-                message.attachments.forEach((attachment) => {
-                    out += `Attachment > ${attachment.url}\n`;
-                });
-            }
-            out += "\n\n";
-        }
-    });
+    const transcript = JSONTranscriptToHumanReadable(JSONTranscriptFromMessageArray(deleted.map((m) => m as Discord.Message))!);
     const attachmentObject = {
-        attachment: Buffer.from(out),
+        attachment: Buffer.from(transcript),
         name: `purge-${channel.id}-${Date.now()}.txt`,
         description: "Purge log"
     };
@@ -240,7 +211,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 {
diff --git a/src/events/guildMemberUpdate.ts b/src/events/guildMemberUpdate.ts
index 0ebfc3d..440d786 100644
--- a/src/events/guildMemberUpdate.ts
+++ b/src/events/guildMemberUpdate.ts
@@ -1,4 +1,4 @@
-import type { GuildAuditLogsEntry, GuildMember } from "discord.js";
+import { AuditLogEvent, GuildAuditLogsEntry, GuildMember } from "discord.js";
 import type { NucleusClient } from "../utils/client.js";
 
 export const event = "guildMemberUpdate";
@@ -6,9 +6,9 @@
 export async function callback(client: NucleusClient, before: GuildMember, after: GuildMember) {
     try {
         const { log, NucleusColors, entry, renderUser, renderDelta, getAuditLog } = client.logger;
-        const auditLog = await getAuditLog(after.guild, "MEMBER_UPDATE");
+        const auditLog = await getAuditLog(after.guild, AuditLogEvent.MemberUpdate);
         const audit = auditLog.entries.filter((entry: GuildAuditLogsEntry) => entry.target!.id === after.id).first();
-        if (audit.executor.id === client.user.id) return;
+        if (audit.executor.id === client.user!.id) return;
         if (before.nickname !== after.nickname) {
             await client.database.history.create(
                 "nickname",
diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts
index 2f3a077..69bc542 100644
--- a/src/events/messageCreate.ts
+++ b/src/events/messageCreate.ts
@@ -1,7 +1,7 @@
 import type { NucleusClient } from "../utils/client.js";
 import { LinkCheck, MalwareCheck, NSFWCheck, SizeCheck, TestString, TestImage } from "../reflex/scanners.js";
 import logAttachment from "../premium/attachmentLogs.js";
-import createLogException from "../utils/createLogException.js";
+import { messageException } from "../utils/createTemporaryStorage.js";
 import getEmojiByName from "../utils/getEmojiByName.js";
 import client from "../utils/client.js";
 import { callback as statsChannelUpdate } from "../reflex/statsChannelUpdate.js";
@@ -48,7 +48,7 @@
     if (config.filters.invite.enabled) {
         if (!config.filters.invite.allowed.channels.includes(message.channel.id)) {
             if (/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(content)) {
-                createLogException(message.guild.id, message.channel.id, message.id);
+                messageException(message.guild.id, message.channel.id, message.id);
                 message.delete();
                 const data = {
                     meta: {
@@ -84,7 +84,7 @@
                     !(message.channel instanceof ThreadChannel ? message.channel.parent?.nsfw : message.channel.nsfw)
                 ) {
                     if (await NSFWCheck(url)) {
-                        createLogException(message.guild.id, message.channel.id, message.id);
+                        messageException(message.guild.id, message.channel.id, message.id);
                         await message.delete();
                         const data = {
                             meta: {
@@ -119,7 +119,7 @@
                         config.filters.wordFilter.words.strict
                     );
                     if (check !== null) {
-                        createLogException(message.guild.id, message.channel.id, message.id);
+                        messageException(message.guild.id, message.channel.id, message.id);
                         await message.delete();
                         const data = {
                             meta: {
@@ -149,7 +149,7 @@
                 if (config.filters.images.size) {
                     if (url.match(/\.+(webp|png|jpg)$/gi)) {
                         if (!(await SizeCheck(element))) {
-                            createLogException(message.guild.id, message.channel.id, message.id);
+                            messageException(message.guild.id, message.channel.id, message.id);
                             await message.delete();
                             const data = {
                                 meta: {
@@ -180,7 +180,7 @@
             }
             if (config.filters.malware) {
                 if (!(await MalwareCheck(url))) {
-                    createLogException(message.guild.id, message.channel.id, message.id);
+                    messageException(message.guild.id, message.channel.id, message.id);
                     await message.delete();
                     const data = {
                         meta: {
@@ -212,7 +212,7 @@
 
     const linkDetectionTypes = await LinkCheck(message);
     if (linkDetectionTypes.length > 0) {
-        createLogException(message.guild.id, message.channel.id, message.id);
+        messageException(message.guild.id, message.channel.id, message.id);
         await message.delete();
         const data = {
             meta: {
@@ -244,7 +244,7 @@
             config.filters.wordFilter.words.strict
         );
         if (check !== null) {
-            createLogException(message.guild.id, message.channel.id, message.id);
+            messageException(message.guild.id, message.channel.id, message.id);
             await message.delete();
             const data = {
                 meta: {
@@ -293,7 +293,7 @@
     if (config.filters.pings.roles) {
         for (const roleId in message.mentions.roles) {
             if (!config.filters.pings.allowed.roles.includes(roleId)) {
-                createLogException(message.guild.id, message.channel.id, message.id);
+                messageException(message.guild.id, message.channel.id, message.id);
                 await message.delete();
                 const data = {
                     meta: {
@@ -319,7 +319,7 @@
         }
     }
     if (message.mentions.users.size >= config.filters.pings.mass && config.filters.pings.mass) {
-        createLogException(message.guild.id, message.channel.id, message.id);
+        messageException(message.guild.id, message.channel.id, message.id);
         await message.delete();
         const data = {
             meta: {
diff --git a/src/index.ts b/src/index.ts
index aff1b2b..362b805 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -9,14 +9,9 @@
     register();
     runServer(client);
 });
-process.on("unhandledRejection", (err) => {
-    console.error(err);
-});
-process.on("uncaughtException", (err) => {
-    console.error(err);
-});
+process.on("unhandledRejection", (err) => { console.error(err) });
+process.on("uncaughtException", (err) => { console.error(err) });
 
-if (config.enableDevelopment) { await client.login(config.developmentToken); }
-else { await client.login(config.token); }
+await client.login(config.enableDevelopment ? config.developmentToken : config.token)
 
 await recordPerformance();
\ No newline at end of file
diff --git a/src/premium/createTranscript.ts b/src/premium/createTranscript.ts
index e755b83..f09ac92 100644
--- a/src/premium/createTranscript.ts
+++ b/src/premium/createTranscript.ts
@@ -113,7 +113,10 @@
     }
     let i;
     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 }
+        });
         i.deferUpdate();
     } catch {
         return;
diff --git a/src/reflex/guide.ts b/src/reflex/guide.ts
index 842951c..b539aac 100644
--- a/src/reflex/guide.ts
+++ b/src/reflex/guide.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../utils/defaultEmbeds.js";
+import { LoadingEmbed } from "../utils/defaults.js";
 import Discord, {
     ActionRowBuilder,
     ButtonBuilder,
@@ -225,7 +225,7 @@
     }
     let page = 0;
 
-    const f = async (component: MessageComponentInteraction) => {
+    const publicFilter = async (component: MessageComponentInteraction) => {
         return (component.member as Discord.GuildMember).permissions.has("MANAGE_GUILD");
     };
 
@@ -293,10 +293,8 @@
         try {
             i = await m.awaitMessageComponent({
                 filter: interaction
-                    ? () => {
-                          return true;
-                      }
-                    : f,
+                    ? (i) => { return i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id }
+                    : publicFilter,
                 time: 300000
             });
         } catch (e) {
diff --git a/src/reflex/verify.ts b/src/reflex/verify.ts
index 2372130..4977c64 100644
--- a/src/reflex/verify.ts
+++ b/src/reflex/verify.ts
@@ -1,4 +1,4 @@
-import { LoadingEmbed } from "./../utils/defaultEmbeds.js";
+import { LoadingEmbed, unknownServerIcon } from "../utils/defaults.js";
 import Discord, {
     CommandInteraction,
     GuildMember,
@@ -215,7 +215,7 @@
         rName: role.name,
         uName: interaction.member!.user.username,
         gName: interaction.guild!.name,
-        gIcon: interaction.guild!.iconURL({ extension: "png", size: 256 }) ?? "https://assets-global.website-files.com/6257adef93867e50d84d30e2/636e0a6a49cf127bf92de1e2_icon_clyde_blurple_RGB.png",
+        gIcon: interaction.guild!.iconURL({ extension: "png", size: 256 }) ?? unknownServerIcon,
         interaction: interaction as MessageComponentInteraction
     };
     await interaction.editReply({
diff --git a/src/utils/calculate.ts b/src/utils/calculate.ts
index 98d82c3..0bd5a9f 100644
--- a/src/utils/calculate.ts
+++ b/src/utils/calculate.ts
@@ -23,7 +23,7 @@
 
 const tickets = ["support", "report", "question", "issue", "suggestion", "other"];
 
-const toHexInteger = (permissions: string[], array?: string[]) => {
+const toHexInteger = (permissions: string[], array?: string[]): string => {
     if (!array) {
         array = logs;
     }
@@ -35,18 +35,18 @@
     return int.toString(16);
 };
 
-const toHexArray = (permissionsHex: string, array?: string[]) => {
+const toHexArray = (permissionsHex: string, array?: string[]): string[] => {
     if (!array) {
         array = logs;
     }
-    const permissions = [];
+    const permissions: string[] = [];
     const int = BigInt("0x" + permissionsHex)
         .toString(2)
         .split("")
         .reverse();
     for (const index in int) {
         if (int[index] === "1" && array.length > parseInt(index)) {
-            permissions.push(array[index]);
+            permissions.push(array[index]!);
         }
     }
     return permissions;
diff --git a/src/utils/client.ts b/src/utils/client.ts
index 43cbe11..46d9f92 100644
--- a/src/utils/client.ts
+++ b/src/utils/client.ts
@@ -23,6 +23,7 @@
         eventScheduler: EventScheduler;
         performanceTest: PerformanceTest;
     };
+    preloadPage: Record<string, {command: string, argument: string}> = {};  // e.g. { channelID: { command: privacy, page: 3}}
     commands: Record<string, {
         command: Discord.SlashCommandBuilder |
                 ((builder: Discord.SlashCommandBuilder) => Discord.SlashCommandBuilder) |
diff --git a/src/utils/commandRegistration/register.ts b/src/utils/commandRegistration/register.ts
index d96ca90..fdae167 100644
--- a/src/utils/commandRegistration/register.ts
+++ b/src/utils/commandRegistration/register.ts
@@ -1,8 +1,10 @@
+import type { CommandInteraction } from 'discord.js';
 import Discord, { Interaction, SlashCommandBuilder, ApplicationCommandType } from 'discord.js';
 import config from "../../config/main.json" assert { type: "json" };
 import client from "../client.js";
 import fs from "fs";
-
+import EmojiEmbed from '../generateEmojiEmbed.js';
+import getEmojiByName from '../getEmojiByName.js';
 
 const colours = {
     red: "\x1b[31m",
@@ -174,17 +176,25 @@
     });
 }
 
-async function execute(check: Function | undefined, callback: Function | undefined, data: Interaction) {
+async function execute(check: Function | undefined, callback: Function | undefined, data: CommandInteraction) {
     if (!callback) return;
     if (check) {
         let result;
         try {
             result = await check(data);
-        } catch (e) {
-            console.log(e);
+        } catch(e) {
             result = false;
         }
-        if (!result) return;
+        if (result === false) return;
+        if (typeof result === "string") {
+            const { NucleusColors } = client.logger
+            return data.reply({embeds: [new EmojiEmbed()
+                .setTitle("")
+                .setDescription(result)
+                .setColor(NucleusColors.red)
+                .setEmoji(getEmojiByName("CONTROL.BLOCKCROSS"))
+            ]});
+        };
     }
     callback(data);
 }
diff --git a/src/utils/confirmationMessage.ts b/src/utils/confirmationMessage.ts
index b3202e3..4d90676 100644
--- a/src/utils/confirmationMessage.ts
+++ b/src/utils/confirmationMessage.ts
@@ -183,7 +183,7 @@
             let component;
             try {
                 component = await m.awaitMessageComponent({
-                    filter: (m) => m.user.id === this.interaction.user.id,
+                    filter: (m) => m.user.id === this.interaction.user.id && m.channel!.id === this.interaction.channel!.id,
                     time: 300000
                 });
             } catch (e) {
diff --git a/src/utils/createLogException.ts b/src/utils/createLogException.ts
deleted file mode 100644
index 329f422..0000000
--- a/src/utils/createLogException.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import client from "./client.js";
-
-export default function (guild: string, channel: string, message: string) {
-    client.noLog.push(`${guild}/${channel}/${message}`);
-    setTimeout(() => {
-        client.noLog = client.noLog.filter((i: string) => {
-            return i !== `${guild}/${channel}/${message}`;
-        });
-    }, 500);
-}
diff --git a/src/utils/createTemporaryStorage.ts b/src/utils/createTemporaryStorage.ts
new file mode 100644
index 0000000..a684d9d
--- /dev/null
+++ b/src/utils/createTemporaryStorage.ts
@@ -0,0 +1,32 @@
+import client from "./client.js";
+
+function generalException(location: string) {
+    client.noLog.push(location);
+    setTimeout(() => {
+        client.noLog = client.noLog.filter((i: string) => {
+            return i !== location;
+        });
+    }, 1000);
+}
+
+export function messageException(guild: string, channel: string, message: string) {
+    generalException(`${guild}/${channel}/${message}`);
+}
+
+export function roleException(guild: string, user: string) {
+    generalException(`${guild}/${user}`);
+}
+
+export function preloadPage(target: string, command: string, message: string) {
+    client.preloadPage[target] = {
+        command: command,
+        argument: message
+    }
+    setTimeout(() => {
+        const object = Object.entries(client.preloadPage).filter((entry) => {
+            const [k, _] = entry
+            return k !== target;
+        })
+        client.preloadPage = Object.fromEntries(object);
+    }, 60 * 5 * 1000);
+}
\ No newline at end of file
diff --git a/src/utils/defaultEmbeds.ts b/src/utils/defaults.ts
similarity index 73%
rename from src/utils/defaultEmbeds.ts
rename to src/utils/defaults.ts
index a027c76..1331ce1 100644
--- a/src/utils/defaultEmbeds.ts
+++ b/src/utils/defaults.ts
@@ -1,3 +1,4 @@
+import type Discord from "discord.js";
 import EmojiEmbed from "./generateEmojiEmbed.js";
 import getEmojiByName from "./getEmojiByName.js";
 
@@ -15,6 +16,7 @@
     title: string = "";
     description = "";
     pageId = 0;
+    componentsToSet: Discord.ActionRowBuilder<Discord.ButtonBuilder | Discord.StringSelectMenuBuilder>[] = [];
 
     setEmbed(embed: EmojiEmbed) {
         this.embed = embed;
@@ -32,6 +34,12 @@
         this.pageId = pageId;
         return this;
     }
+    setComponents(components: Discord.ActionRowBuilder<Discord.ButtonBuilder | Discord.StringSelectMenuBuilder>[]) {
+        this.componentsToSet = components;
+        return this;
+    }
 }
 
 export { Embed };
+
+export const unknownServerIcon = "";
diff --git a/src/utils/getCommandMentionByName.ts b/src/utils/getCommandMentionByName.ts
new file mode 100644
index 0000000..b2b9937
--- /dev/null
+++ b/src/utils/getCommandMentionByName.ts
@@ -0,0 +1,22 @@
+import type Discord from "discord.js";
+import client from "./client.js";
+import config from "../config/main.json" assert { type: "json"};
+
+
+export const getCommandMentionByName = async (name: string): Promise<string> => {
+    const split = name.replaceAll("/", " ").split(" ")
+    const commandName: string = split[0]!;
+    let commandID: string;
+
+    const filterCommand = (command: Discord.ApplicationCommand) => command.name === commandName;
+
+    if (config.enableDevelopment) {
+        const developmentGuild = client.guilds.cache.get(config.developmentGuildID)!;
+        await developmentGuild.commands.fetch();
+        commandID = developmentGuild.commands.cache.filter(c => filterCommand(c)).first()!.id;
+    } else {
+        await client.application?.commands.fetch();
+        commandID = client.application?.commands.cache.filter(c => filterCommand(c)).first()!.id!;
+    }
+    return `</${split.join(" ")}:${commandID}>`;
+}
\ No newline at end of file
diff --git a/src/utils/log.ts b/src/utils/log.ts
index 7ab7903..3f46f86 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -26,6 +26,7 @@
         return `${num1} -> ${num2} (${delta > 0 ? "+" : ""}${delta})`;
     },
     entry(value: string | number | null, displayValue: string): { value: string | null; displayValue: string } {
+        if (typeof value === "number") value = value.toString();
         return { value: value, displayValue: displayValue };
     },
     renderChannel(channel: Discord.GuildChannel | Discord.ThreadChannel) {
diff --git a/src/utils/logTranscripts.ts b/src/utils/logTranscripts.ts
index d5ab0b2..0950664 100644
--- a/src/utils/logTranscripts.ts
+++ b/src/utils/logTranscripts.ts
@@ -1,3 +1,64 @@
-function JSONTranscriptFromMessageArray(messages: Discord.Message[]) {
-    
+import type Discord from 'discord.js';
+
+export interface JSONTranscriptSchema {
+    messages: {
+        content: string | null;
+        attachments: {
+            url: string;
+            name: string;
+            size: number;
+        }[];
+        authorID: string;
+        authorUsername: string;
+        authorUsernameColor: string;
+        timestamp: string;
+        id: string;
+        edited: boolean;
+    }[];
+    channel: string;
+    guild: string;
+    timestamp: string;
+}
+
+
+export const JSONTranscriptFromMessageArray = (messages: Discord.Message[]): JSONTranscriptSchema | null => {
+    if (messages.length === 0) return null;
+    return {
+        guild: messages[0]!.guild!.id,
+        channel: messages[0]!.channel.id,
+        timestamp: Date.now().toString(),
+        messages: messages.map((message: Discord.Message) => {
+            return {
+                content: message.content,
+                attachments: message.attachments.map((attachment: Discord.Attachment) => {
+                    return {
+                        url: attachment.url,
+                        name: attachment.name!,
+                        size: attachment.size,
+                    };
+                }),
+                authorID: message.author.id,
+                authorUsername: message.author.username + "#" + message.author.discriminator,
+                authorUsernameColor: message.member!.displayHexColor.toString(),
+                timestamp: message.createdTimestamp.toString(),
+                id: message.id,
+                edited: message.editedTimestamp ? true : false,
+            };
+        })
+    };
+}
+
+export const JSONTranscriptToHumanReadable = (data: JSONTranscriptSchema): string => {
+    let out = "";
+
+    for (const message of data.messages) {
+        const date = new Date(parseInt(message.timestamp));
+        out += `${message.authorUsername} (${message.authorID}) [${date}]`;
+        if (message.edited) out += " (edited)";
+        if (message.content) out += "\nContent:\n" + message.content.split("\n").map((line: string) => `\n> ${line}`).join("");
+        if (message.attachments.length > 0) out += "\nAttachments:\n" + message.attachments.map((attachment: { url: string; name: string; size: number; }) => `\n> [${attachment.name}](${attachment.url}) (${attachment.size} bytes)`).join("\n");
+
+        out += "\n\n";
+    }
+    return out;
 }
\ No newline at end of file
diff --git a/src/utils/performanceTesting/record.ts b/src/utils/performanceTesting/record.ts
index 9f840af..95761e9 100644
--- a/src/utils/performanceTesting/record.ts
+++ b/src/utils/performanceTesting/record.ts
@@ -29,6 +29,7 @@
 }
 
 const record = async () => {
+    if (config.enableDevelopment) return;
     const results = {
         discord: discordPing(),
         databaseRead: await databaseReadTime(),