worked on scanners, database, tracks, some moving around and cleaning up files.
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
index 8796892..9528183 100644
--- a/src/commands/settings/rolemenu.ts
+++ b/src/commands/settings/rolemenu.ts
@@ -8,6 +8,7 @@
 import createPageIndicator from "../../utils/createPageIndicator.js";
 import { configToDropdown } from "../../actions/roleMenu.js";
 import { modalInteractionCollector } from "../../utils/dualCollector.js";
+import ellipsis from "../../utils/ellipsis.js";
 import lodash from 'lodash';
 
 const isEqual = lodash.isEqual;
@@ -44,8 +45,9 @@
         .addComponents(
             new StringSelectMenuBuilder()
                 .setCustomId("reorder")
-                .setPlaceholder("Select a page to move...")
-                .setMinValues(1)
+                .setPlaceholder("Select all pages in the order you want them to appear.")
+                .setMinValues(currentObj.length)
+                .setMaxValues(currentObj.length)
                 .addOptions(
                     currentObj.map((o, i) => new StringSelectMenuOptionBuilder()
                         .setLabel(o.name)
@@ -81,6 +83,7 @@
         out = null;
     }
     if(!out) return;
+    out.deferUpdate();
     if (out.isButton()) return;
     if(!out.values) return;
     const values = out.values;
@@ -160,12 +163,7 @@
 
 }
 
-const ellipsis = (str: string, max: number): string => {
-    if (str.length <= max) return str;
-    return str.slice(0, max - 3) + "...";
-}
-
-const createRoleMenuPage = async (interaction: StringSelectMenuInteraction | ButtonInteraction, m: Message, data?: ObjectSchema): Promise<ObjectSchema | null> => {
+const editRoleMenuPage = async (interaction: StringSelectMenuInteraction | ButtonInteraction, m: Message, data?: ObjectSchema): Promise<ObjectSchema | null> => {
     if (!data) data = {
         name: "Role Menu Page",
         description: "A new role menu page",
@@ -321,7 +319,7 @@
     let modified = false;
     do {
         const embed = new EmojiEmbed()
-            .setTitle("Role Menu Settings")
+            .setTitle("Role Menu")
             .setEmoji("GUILD.GREEN")
             .setStatus("Success");
         const noRoleMenus = currentObject.length === 0;
@@ -377,7 +375,7 @@
                     .setDisabled(!modified),
             );
         if(noRoleMenus) {
-            embed.setDescription("No role menu page have been set up yet. Use the button below to add one.\n\n" +
+            embed.setDescription("No role menu pages have been set up yet. Use the button below to add one.\n\n" +
                 createPageIndicator(1, 1, undefined, true)
             );
             pageSelect.setDisabled(true);
@@ -390,7 +388,7 @@
             page = Math.min(page, Object.keys(currentObject).length - 1);
             current = currentObject[page]!;
             embed.setDescription(`**Currently Editing:** ${current.name}\n\n` +
-                `**Description:** \`${current.description}\`\n` +
+                `**Description:**\n> ${current.description}\n` +
                 `\n\n${createPageIndicator(Object.keys(config.roleMenu.options).length, page)}`
             );
 
@@ -424,7 +422,7 @@
                     page++;
                     break;
                 case "add":
-                    let newPage = await createRoleMenuPage(i, m)
+                    let newPage = await editRoleMenuPage(i, m)
                     if(!newPage) break;
                     currentObject.push();
                     page = currentObject.length - 1;
@@ -444,7 +442,7 @@
                 case "action":
                     switch(i.values[0]) {
                         case "edit":
-                            let edited = await createRoleMenuPage(i, m, current!);
+                            let edited = await editRoleMenuPage(i, m, current!);
                             if(!edited) break;
                             currentObject[page] = edited;
                             modified = true;
diff --git a/src/commands/settings/tracks.ts b/src/commands/settings/tracks.ts
index 0cad55c..782f52f 100644
--- a/src/commands/settings/tracks.ts
+++ b/src/commands/settings/tracks.ts
@@ -1,16 +1,405 @@
-import type { CommandInteraction, GuildMember, SlashCommandSubcommandBuilder } from "discord.js";
+import { ActionRowBuilder, APIMessageComponentEmoji, ButtonBuilder, ButtonInteraction, ButtonStyle, Collection, CommandInteraction, GuildMember, Message, ModalBuilder, ModalSubmitInteraction, Role, RoleSelectMenuBuilder, RoleSelectMenuInteraction, SlashCommandSubcommandBuilder, StringSelectMenuBuilder, StringSelectMenuInteraction, StringSelectMenuOptionBuilder, TextInputBuilder, TextInputStyle } from "discord.js";
 import client from "../../utils/client.js";
-
+import createPageIndicator, { createVerticalTrack } from "../../utils/createPageIndicator.js";
+import { LoadingEmbed } from "../../utils/defaults.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import getEmojiByName from "../../utils/getEmojiByName.js";
+import ellipsis from "../../utils/ellipsis.js";
+import { modalInteractionCollector } from "../../utils/dualCollector.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
         .setName("tracks")
         .setDescription("Manage the tracks for the server")
 
+interface ObjectSchema {
+    name: string;
+    retainPrevious: boolean;
+    nullable: boolean;
+    track: string[];
+    manageableBy: string[];
+}
+
+const editName = async (i: ButtonInteraction, interaction: StringSelectMenuInteraction | ButtonInteraction, m: Message, current?: string) => {
+
+    let name = current ?? "";
+    const modal = new ModalBuilder()
+        .setTitle("Edit Name and Description")
+        .setCustomId("editNameDescription")
+        .addComponents(
+            new ActionRowBuilder<TextInputBuilder>()
+                .addComponents(
+                    new TextInputBuilder()
+                        .setLabel("Name")
+                        .setCustomId("name")
+                        .setPlaceholder("Name here...") // TODO: Make better placeholder
+                        .setStyle(TextInputStyle.Short)
+                        .setValue(name ?? "")
+                        .setRequired(true)
+                )
+        )
+    const button = new ActionRowBuilder<ButtonBuilder>()
+        .addComponents(
+            new ButtonBuilder()
+                .setCustomId("back")
+                .setLabel("Back")
+                .setStyle(ButtonStyle.Secondary)
+                .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
+        )
+
+    await i.showModal(modal)
+    await interaction.editReply({
+        embeds: [
+            new EmojiEmbed()
+                .setTitle("Tracks")
+                .setDescription("Modal opened. If you can't see it, click back and try again.")
+                .setStatus("Success")
+        ],
+        components: [button]
+    });
+
+    let out: ModalSubmitInteraction | null;
+    try {
+        out = await modalInteractionCollector(
+            m,
+            (m) => m.channel!.id === interaction.channel!.id,
+            (_) => true
+        ) as ModalSubmitInteraction | null;
+    } catch (e) {
+        console.error(e);
+        out = null;
+    }
+    if(!out) return name;
+    if (out.isButton()) return name;
+    if(!out.fields) return name;
+    name = out.fields.fields.find((f) => f.customId === "name")?.value ?? name;
+    return name
+
+}
+
+const reorderTracks = async (interaction: ButtonInteraction, m: Message, roles: Collection<string, Role>, currentObj: string[]) => {
+    let reorderRow = new ActionRowBuilder<StringSelectMenuBuilder>()
+        .addComponents(
+            new StringSelectMenuBuilder()
+                .setCustomId("reorder")
+                .setPlaceholder("Select all roles in the order you want users to gain them (Lowest to highest rank).")
+                .setMinValues(currentObj.length)
+                .setMaxValues(currentObj.length)
+                .addOptions(
+                    currentObj.map((o, i) => new StringSelectMenuOptionBuilder()
+                        .setLabel(roles.get(o)!.name)
+                        .setValue(i.toString())
+                    )
+                )
+        );
+    let buttonRow = new ActionRowBuilder<ButtonBuilder>()
+        .addComponents(
+            new ButtonBuilder()
+                .setCustomId("back")
+                .setLabel("Back")
+                .setStyle(ButtonStyle.Secondary)
+                .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
+        )
+    await interaction.editReply({
+        embeds: [
+            new EmojiEmbed()
+                .setTitle("Tracks")
+                .setDescription("Select all roles in the order you want users to gain them (Lowest to highest rank).")
+                .setStatus("Success")
+        ],
+        components: [reorderRow, buttonRow]
+    });
+    let out: StringSelectMenuInteraction | ButtonInteraction | null;
+    try {
+        out = await m.awaitMessageComponent({
+            filter: (i) => i.channel!.id === interaction.channel!.id,
+            time: 300000
+        }) as StringSelectMenuInteraction | ButtonInteraction | null;
+    } catch (e) {
+        console.error(e);
+        out = null;
+    }
+    if(!out) return;
+    out.deferUpdate();
+    if (out.isButton()) return;
+    if(!out.values) return;
+    const values = out.values;
+
+    const newOrder: string[] = currentObj.map((_, i) => {
+        const index = values.findIndex(v => v === i.toString());
+        return currentObj[index];
+    }) as string[];
+
+    return newOrder;
+}
+
+const editTrack = async (interaction: ButtonInteraction | StringSelectMenuInteraction, message: Message, roles: Collection<string, Role>, current?: ObjectSchema) => {
+    if(!current) {
+        current = {
+            name: "",
+            retainPrevious: false,
+            nullable: false,
+            track: [],
+            manageableBy: []
+        }
+    }
+    const buttons = new ActionRowBuilder<ButtonBuilder>()
+        .addComponents(
+            new ButtonBuilder()
+                .setCustomId("back")
+                .setLabel("Back")
+                .setStyle(ButtonStyle.Secondary)
+                .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
+            new ButtonBuilder()
+                .setCustomId("edit")
+                .setLabel("Edit Name")
+                .setStyle(ButtonStyle.Primary)
+                .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
+            new ButtonBuilder()
+                .setCustomId("reorder")
+                .setLabel("Reorder")
+                .setStyle(ButtonStyle.Primary)
+                .setEmoji(getEmojiByName("ICONS.REORDER", "id") as APIMessageComponentEmoji),
+        );
+    const roleSelect = new ActionRowBuilder<RoleSelectMenuBuilder>()
+        .addComponents(
+            new RoleSelectMenuBuilder()
+                .setCustomId("addRole")
+                .setPlaceholder("Select a role to add")
+        );
+    let closed = false;
+    do {
+        const editableRoles: string[] = current.track.map((r) => {
+            if(!(roles.get(r)!.position >= (interaction.member as GuildMember).roles.highest.position)) return r;
+        }).filter(v => v !== undefined) as string[];
+        const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
+            .addComponents(
+                new StringSelectMenuBuilder()
+                    .setCustomId("removeRole")
+                    .setPlaceholder("Select a role to remove")
+                    .addOptions(
+                        editableRoles.map((r, i) => {
+                            return new StringSelectMenuOptionBuilder()
+                            .setLabel(r)
+                            .setValue(i.toString())}
+                        )
+                    )
+            );
+        let allowed: boolean[] = [];
+        for (const role of current.track) {
+            const disabled: boolean =
+                roles.get(role)!.position >= (interaction.member as GuildMember).roles.highest.position;
+            allowed.push(disabled)
+        }
+
+        const embed = new EmojiEmbed()
+            .setTitle("Tracks")
+            .setDescription(
+                `**Currently Editing:** ${current.name}\n\n` +
+                `${getEmojiByName} Members ${current.nullable ? "don't " : ""}need a role in this track` +
+                `${getEmojiByName} Members ${current.retainPrevious ? "don't " : ""}keep all roles below their current highest` +
+                createVerticalTrack(current.track, new Array(current.track.length).fill(false), allowed)
+            )
+
+        interaction.editReply({embeds: [embed], components: [buttons, roleSelect, selectMenu]});
+
+        let out: ButtonInteraction | RoleSelectMenuInteraction | StringSelectMenuInteraction | null;
+
+        try {
+            out = await message.awaitMessageComponent({
+                filter: (i) => i.channel!.id === interaction.channel!.id,
+                time: 300000
+            }) as ButtonInteraction | RoleSelectMenuInteraction | StringSelectMenuInteraction | null;
+        } catch (e) {
+            console.error(e);
+            out = null;
+        }
+
+        if(!out) return;
+        if (out.isButton()) {
+            out.deferUpdate();
+            switch(out.customId) {
+                case "back":
+                    closed = true;
+                    break;
+                case "edit":
+                    current.name = (await editName(out, interaction, message, current.name))!;
+                    break;
+                case "reorder":
+                    current.track = (await reorderTracks(out, message, roles, current.track))!;
+            }
+        } else if (out.isStringSelectMenu()) {
+            out.deferUpdate();
+            switch(out.customId) {
+                case "removeRole":
+                    const index = current.track.findIndex(v => v === editableRoles[parseInt((out! as StringSelectMenuInteraction).values![0]!)]);
+                    current.track.splice(index, 1);
+                    break;
+            }
+        } else {
+            switch(out.customId) {
+                case "addRole":
+                    const role = out.values![0]!;
+                    if(!current.track.includes(role)) {
+                        current.track.push(role);
+                    }
+                    out.reply({content: "That role is already on this track", ephemeral: true})
+                    break;
+            }
+        }
+
+    } while(!closed);
+    return current;
+}
 
 const callback = async (interaction: CommandInteraction) => {
 
-    
+    const m = await interaction.reply({embeds: LoadingEmbed, fetchReply: true, ephemeral: true})
+    const config = await client.database.guilds.read(interaction.guild!.id);
+    const tracks: ObjectSchema[] = config.tracks;
+    const roles = await interaction.guild!.roles.fetch();
+    const memberRoles = interaction.member!.roles;
+    const member = interaction.member as GuildMember;
+
+    let page = 0;
+    let closed = false;
+    let modified = false;
+
+    do {
+        const embed = new EmojiEmbed()
+            .setTitle("Track Settings")
+            .setEmoji("TRACKS.ICON")
+            .setStatus("Success");
+        const noTracks = config.tracks.length === 0;
+        let current: ObjectSchema;
+
+        const pageSelect = new StringSelectMenuBuilder()
+            .setCustomId("page")
+            .setPlaceholder("Select a track to manage");
+        const actionSelect = new StringSelectMenuBuilder()
+            .setCustomId("action")
+            .setPlaceholder("Perform an action")
+            .addOptions(
+                new StringSelectMenuOptionBuilder()
+                    .setLabel("Edit")
+                    .setDescription("Edit this track")
+                    .setValue("edit")
+                    .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
+                new StringSelectMenuOptionBuilder()
+                    .setLabel("Delete")
+                    .setDescription("Delete this track")
+                    .setValue("delete")
+                    .setEmoji(getEmojiByName("TICKETS.ISSUE", "id") as APIMessageComponentEmoji)
+        );
+        const buttonRow = new ActionRowBuilder<ButtonBuilder>()
+            .addComponents(
+                new ButtonBuilder()
+                    .setCustomId("back")
+                    .setStyle(ButtonStyle.Primary)
+                    .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji)
+                    .setDisabled(page === 0),
+                new ButtonBuilder()
+                    .setCustomId("next")
+                    .setEmoji(getEmojiByName("CONTROL.RIGHT", "id") as APIMessageComponentEmoji)
+                    .setStyle(ButtonStyle.Primary)
+                    .setDisabled(page === Object.keys(tracks).length - 1),
+                new ButtonBuilder()
+                    .setCustomId("add")
+                    .setLabel("New Track")
+                    .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id") as APIMessageComponentEmoji)
+                    .setStyle(ButtonStyle.Secondary)
+                    .setDisabled(Object.keys(tracks).length >= 24),
+                new ButtonBuilder()
+                    .setCustomId("save")
+                    .setLabel("Save")
+                    .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
+                    .setStyle(ButtonStyle.Success)
+                    .setDisabled(!modified),
+            );
+        if(noTracks) {
+            embed.setDescription("No tracks have been set up yet. Use the button below to add one.\n\n" +
+                createPageIndicator(1, 1, undefined, true)
+            );
+            pageSelect.setDisabled(true);
+            actionSelect.setDisabled(true);
+            pageSelect.addOptions(new StringSelectMenuOptionBuilder()
+                .setLabel("No tracks")
+                .setValue("none")
+            );
+        } else {
+            page = Math.min(page, Object.keys(tracks).length - 1);
+            current = tracks[page]!;
+            embed.setDescription(`**Currently Editing:** ${current.name}\n\n` +
+                `${getEmojiByName("CONTROL." + (current.nullable ? "CROSS" : "TICK"))} Members ${current.nullable ? "don't " : ""}need a role in this track\n` +
+                `${getEmojiByName("CONTROL." + (current.retainPrevious ? "TICK" : "CROSS"))} Members ${current.retainPrevious ? "" : "don't "}keep all roles below their current highest\n\n` +
+                createVerticalTrack(current.track, new Array(current.track.length).fill(false)) +
+                `\n${createPageIndicator(config.tracks.length, page)}`
+            );
+
+            pageSelect.addOptions(
+                tracks.map((key: ObjectSchema, index) => {
+                    return new StringSelectMenuOptionBuilder()
+                        .setLabel(ellipsis(key.name, 50))
+                        .setDescription(ellipsis(roles.get(key.track[0]!)?.name!, 50))
+                        .setValue(index.toString());
+                })
+            );
+
+        }
+
+        await interaction.editReply({embeds: [embed], components: [new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(actionSelect), new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(pageSelect), buttonRow]});
+        let i: StringSelectMenuInteraction | ButtonInteraction;
+        try {
+            i = await m.awaitMessageComponent({ time: 300000, filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id && i.channelId === interaction.channelId}) as ButtonInteraction | StringSelectMenuInteraction;
+        } catch (e) {
+            closed = true;
+            break;
+        }
+
+        await i.deferUpdate();
+        if (i.isButton()) {
+            switch (i.customId) {
+                case "back":
+                    page--;
+                    break;
+                case "next":
+                    page++;
+                    break;
+                case "add":
+                    let newPage = await editTrack(i, m, roles)
+                    if(!newPage) break;
+                    tracks.push();
+                    page = tracks.length - 1;
+                    break;
+                case "save":
+                    // client.database.guilds.write(interaction.guild!.id, {"roleMenu.options": tracks});  // TODO
+                    modified = false;
+                    break;
+            }
+        } else if (i.isStringSelectMenu()) {
+            switch (i.customId) {
+                case "action":
+                    switch(i.values[0]) {
+                        case "edit":
+                            let edited = await editTrack(i, m, roles, current!);
+                            if(!edited) break;
+                            tracks[page] = edited;
+                            modified = true;
+                            break;
+                        case "delete":
+                            if(page === 0 && tracks.keys.length - 1 > 0) page++;
+                            else page--;
+                            tracks.splice(page, 1);
+                            break;
+                    }
+                    break;
+                case "page":
+                    page = parseInt(i.values[0]!);
+                    break;
+            }
+        }
+
+    } while (!closed)
 
 }