From 1e7b22127680bb1b7733e62afd81bf4d0267dea2 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Thu, 21 Mar 2024 18:50:56 +0000 Subject: [PATCH 1/4] WIP: Start of series command --- src/commands/series.ts | 87 ++++++++++++++++++++++++++++++++++++++++++ src/registry.ts | 2 + src/type/command.ts | 4 +- 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/commands/series.ts diff --git a/src/commands/series.ts b/src/commands/series.ts new file mode 100644 index 0000000..ede9186 --- /dev/null +++ b/src/commands/series.ts @@ -0,0 +1,87 @@ +import { CommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js"; +import { Command } from "../type/command"; +import { CoreClient } from "../client/client"; +import EmbedColours from "../constants/EmbedColours"; +import AppLogger from "../client/appLogger"; + +export default class Series extends Command { + constructor() { + super(); + + this.CommandBuilder = new SlashCommandBuilder() + .setName("view") + .setDescription("View details on a series") + .addSubcommand(x => + x + .setName("view") + .setDescription("View a specifiic series by id") + .addStringOption(y => + y + .setName("id") + .setDescription("The series id") + .setRequired(true))) + .addSubcommand(x => + x + .setName("list") + .setDescription("List all series")); + } + + public override async execute(interaction: CommandInteraction) { + if (!interaction.isChatInputCommand()) return; + + switch (interaction.options.getSubcommand()) { + case "view": + await this.ViewSeries(interaction); + break; + case "list": + await this.ListSeries(interaction); + break; + default: + AppLogger.LogWarn("Commands/Series", `Subcommand doesn't exist: ${interaction.options.getSubcommand()}`); + await interaction.reply("Subcommand doesn't exist."); + } + } + + private async ViewSeries(interaction: CommandInteraction) { + const id = interaction.options.get("id"); + + AppLogger.LogSilly("Commands/Series/View", `Parameters: id=${id?.value}`); + + if (!id) return; + + const series = CoreClient.Cards.find(x => x.id == id.value); + + if (!series) { + AppLogger.LogVerbose("Commands/Series/View", "Series not found."); + + await interaction.reply("Series not found."); + return; + } + + const description = series.cards + .map(x => { return `[${x.id}] ${x.name}` }) + .join("\n"); + + const embed = new EmbedBuilder() + .setTitle(series.name) + .setColor(EmbedColours.Ok) + .setDescription(description) + .setFooter({ text: `${series.id} · ${series.cards.length} cards` }); + + await interaction.reply({ embeds: [ embed ]}); + } + + private async ListSeries(interaction: CommandInteraction) { + const description = CoreClient.Cards + .map(x => { return `[${x.id}] ${x.name}` }) + .join("\n"); + + const embed = new EmbedBuilder() + .setTitle("Series") + .setColor(EmbedColours.Ok) + .setDescription(description) + .setFooter({ text: `${CoreClient.Cards.length} series` }); + + await interaction.reply({ embeds: [ embed ]}); + } +} \ No newline at end of file diff --git a/src/registry.ts b/src/registry.ts index 1087cda..05c5714 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -8,6 +8,7 @@ import Gdrivesync from "./commands/gdrivesync"; import Give from "./commands/give"; import Inventory from "./commands/inventory"; import Resync from "./commands/resync"; +import Series from "./commands/series"; import Trade from "./commands/trade"; import View from "./commands/view"; @@ -30,6 +31,7 @@ export default class Registry { CoreClient.RegisterCommand("give", new Give()); CoreClient.RegisterCommand("inventory", new Inventory()); CoreClient.RegisterCommand("resync", new Resync()); + CoreClient.RegisterCommand("series", new Series()); CoreClient.RegisterCommand("trade", new Trade()); CoreClient.RegisterCommand("view", new View()); diff --git a/src/type/command.ts b/src/type/command.ts index 20f5e3a..409a4ca 100644 --- a/src/type/command.ts +++ b/src/type/command.ts @@ -1,7 +1,7 @@ -import { CommandInteraction, SlashCommandBuilder } from "discord.js"; +import { CommandInteraction } from "discord.js"; export abstract class Command { - public CommandBuilder: Omit; + public CommandBuilder: any; abstract execute(interaction: CommandInteraction): Promise; } -- 2.43.4 From 0d520066cf28432fd216f3c2b5df138c17a1322f Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Fri, 22 Mar 2024 19:03:04 +0000 Subject: [PATCH 2/4] WIP: Paginate series --- src/buttonEvents/Series.ts | 45 +++++++++++++++++ src/commands/series.ts | 25 ++-------- src/helpers/SeriesHelper.ts | 98 +++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 20 deletions(-) create mode 100644 src/buttonEvents/Series.ts create mode 100644 src/helpers/SeriesHelper.ts diff --git a/src/buttonEvents/Series.ts b/src/buttonEvents/Series.ts new file mode 100644 index 0000000..357a963 --- /dev/null +++ b/src/buttonEvents/Series.ts @@ -0,0 +1,45 @@ +import { ButtonInteraction } from "discord.js"; +import { ButtonEvent } from "../type/buttonEvent"; +import AppLogger from "../client/appLogger"; +import SeriesHelper from "../helpers/SeriesHelper"; + +export default class Series extends ButtonEvent { + public override async execute(interaction: ButtonInteraction) { + const subaction = interaction.customId.split(" ")[1]; + + switch(subaction) { + case "view": + await this.ViewSeries(interaction); + break; + case "list": + await this.ListSeries(interaction); + break; + default: + AppLogger.LogWarn("Commands/Series", `Subaction doesn't exist: ${subaction}`); + interaction.reply("Subaction doesn't exist."); + } + } + + private async ViewSeries(interaction: ButtonInteraction) { + const seriesid = interaction.customId.split(" ")[2]; + const page = interaction.customId.split(" ")[3]; + + const embed = SeriesHelper.GenerateSeriesViewPage(Number(seriesid), Number(page)); + + await interaction.update({ + embeds: [ embed!.embed ], + components: [ embed!.row ], + }); + } + + private async ListSeries(interaction: ButtonInteraction) { + const page = interaction.customId.split(" ")[2]; + + const embed = SeriesHelper.GenerateSeriesListPage(Number(page)); + + await interaction.update({ + embeds: [ embed!.embed ], + components: [ embed!.row ], + }); + } +} \ No newline at end of file diff --git a/src/commands/series.ts b/src/commands/series.ts index ede9186..422606c 100644 --- a/src/commands/series.ts +++ b/src/commands/series.ts @@ -3,6 +3,7 @@ import { Command } from "../type/command"; import { CoreClient } from "../client/client"; import EmbedColours from "../constants/EmbedColours"; import AppLogger from "../client/appLogger"; +import SeriesHelper from "../helpers/SeriesHelper"; export default class Series extends Command { constructor() { @@ -58,30 +59,14 @@ export default class Series extends Command { return; } - const description = series.cards - .map(x => { return `[${x.id}] ${x.name}` }) - .join("\n"); + const embed = SeriesHelper.GenerateSeriesViewPage(series.id, 0); - const embed = new EmbedBuilder() - .setTitle(series.name) - .setColor(EmbedColours.Ok) - .setDescription(description) - .setFooter({ text: `${series.id} · ${series.cards.length} cards` }); - - await interaction.reply({ embeds: [ embed ]}); + await interaction.reply({ embeds: [ embed!.embed ], components: [ embed!.row ]}); } private async ListSeries(interaction: CommandInteraction) { - const description = CoreClient.Cards - .map(x => { return `[${x.id}] ${x.name}` }) - .join("\n"); + const embed = SeriesHelper.GenerateSeriesListPage(0); - const embed = new EmbedBuilder() - .setTitle("Series") - .setColor(EmbedColours.Ok) - .setDescription(description) - .setFooter({ text: `${CoreClient.Cards.length} series` }); - - await interaction.reply({ embeds: [ embed ]}); + await interaction.reply({ embeds: [ embed!.embed ], components: [ embed!.row ]}); } } \ No newline at end of file diff --git a/src/helpers/SeriesHelper.ts b/src/helpers/SeriesHelper.ts new file mode 100644 index 0000000..0acb6df --- /dev/null +++ b/src/helpers/SeriesHelper.ts @@ -0,0 +1,98 @@ +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js"; +import AppLogger from "../client/appLogger"; +import cloneDeep from "clone-deep"; +import { CoreClient } from "../client/client"; +import EmbedColours from "../constants/EmbedColours"; + +export default class SeriesHelper { + public static GenerateSeriesViewPage(seriesId: number, page: number): { embed: EmbedBuilder, row: ActionRowBuilder } | null { + AppLogger.LogSilly("Helpers/SeriesHelper", `Parameters: seriesId=${seriesId}, page=${page}`); + + const itemsPerPage = 15; + + const series = cloneDeep(CoreClient.Cards) + .find(x => x.id == seriesId); + + if (!series) { + AppLogger.LogVerbose("Helpers/SeriesHelper", `Unable to find series: ${seriesId}`); + return null; + } + + const totalPages = Math.ceil(series.cards.length / itemsPerPage); + + if (page > totalPages) { + AppLogger.LogVerbose("Helpers/SeriesHelper", `Trying to find page greater than what exists for this series. Page: ${page} but there are only ${totalPages} pages`); + return null; + } + + const cardsOnPage = series.cards.splice(page * itemsPerPage, itemsPerPage); + + const description = cardsOnPage + .map(x => `[${x.id}] ${x.name}`) + .join("\n"); + + const embed = new EmbedBuilder() + .setTitle(series.name) + .setColor(EmbedColours.Ok) + .setDescription(description) + .setFooter({ text: `${series.id} · ${series.cards.length} cards · Page ${page + 1} of ${totalPages}` }); + + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId(`series view ${seriesId} ${page - 1}`) + .setLabel("Previous") + .setStyle(ButtonStyle.Primary) + .setDisabled(page == 0), + new ButtonBuilder() + .setCustomId(`series view ${seriesId} ${page + 1}`) + .setLabel("Next") + .setStyle(ButtonStyle.Primary) + .setDisabled(page + 1 > totalPages)); + + return { embed, row }; + } + + public static GenerateSeriesListPage(page: number): { embed: EmbedBuilder, row: ActionRowBuilder } | null { + AppLogger.LogSilly("Helpers/InventoryHelper", `Parameters: page=${page}`); + + const itemsPerPage = 15; + + const series = cloneDeep(CoreClient.Cards) + .sort((a, b) => a.id - b.id); + + const totalPages = Math.ceil(series.length / itemsPerPage); + + if (page > totalPages) { + AppLogger.LogVerbose("Helpers/SeriesHelper", `Trying to find page greater than what exists for this series. Page: ${page} but there are only ${totalPages} pages`); + return null; + } + + const seriesOnPage = series.splice(page * itemsPerPage, itemsPerPage); + + const description = seriesOnPage + .map(x => `[${x.id}] ${x.name}`) + .join("\n"); + + const embed = new EmbedBuilder() + .setTitle("Series") + .setColor(EmbedColours.Ok) + .setDescription(description) + .setFooter({ text: `${CoreClient.Cards.length} series · Page ${page + 1} of ${totalPages}` }); + + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setCustomId(`series list ${page - 1}`) + .setLabel("Previous") + .setStyle(ButtonStyle.Primary) + .setDisabled(page == 0), + new ButtonBuilder() + .setCustomId(`series list ${page + 1}`) + .setLabel("Next") + .setStyle(ButtonStyle.Primary) + .setDisabled(page + 1 > totalPages)); + + return { embed, row }; + } +} \ No newline at end of file -- 2.43.4 From 9e2e2abce31ad9c7c1048ea4a56376bc3ccf88a5 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Mon, 25 Mar 2024 19:03:58 +0000 Subject: [PATCH 3/4] Add series command --- src/commands/series.ts | 2 +- src/helpers/SeriesHelper.ts | 3 ++- src/registry.ts | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/commands/series.ts b/src/commands/series.ts index 422606c..ee82b76 100644 --- a/src/commands/series.ts +++ b/src/commands/series.ts @@ -10,7 +10,7 @@ export default class Series extends Command { super(); this.CommandBuilder = new SlashCommandBuilder() - .setName("view") + .setName("series") .setDescription("View details on a series") .addSubcommand(x => x diff --git a/src/helpers/SeriesHelper.ts b/src/helpers/SeriesHelper.ts index 0acb6df..32b1405 100644 --- a/src/helpers/SeriesHelper.ts +++ b/src/helpers/SeriesHelper.ts @@ -3,6 +3,7 @@ import AppLogger from "../client/appLogger"; import cloneDeep from "clone-deep"; import { CoreClient } from "../client/client"; import EmbedColours from "../constants/EmbedColours"; +import { CardRarityToString } from "../constants/CardRarity"; export default class SeriesHelper { public static GenerateSeriesViewPage(seriesId: number, page: number): { embed: EmbedBuilder, row: ActionRowBuilder } | null { @@ -28,7 +29,7 @@ export default class SeriesHelper { const cardsOnPage = series.cards.splice(page * itemsPerPage, itemsPerPage); const description = cardsOnPage - .map(x => `[${x.id}] ${x.name}`) + .map(x => `[${x.id}] ${x.name} ${CardRarityToString(x.type).toUpperCase()}`) .join("\n"); const embed = new EmbedBuilder() diff --git a/src/registry.ts b/src/registry.ts index 05c5714..bb68685 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -20,6 +20,7 @@ import Droprarity from "./commands/stage/droprarity"; import Claim from "./buttonEvents/Claim"; import InventoryButtonEvent from "./buttonEvents/Inventory"; import Reroll from "./buttonEvents/Reroll"; +import SeriesEvent from "./buttonEvents/Series"; import TradeButtonEvent from "./buttonEvents/Trade"; export default class Registry { @@ -48,6 +49,7 @@ export default class Registry { CoreClient.RegisterButtonEvent("claim", new Claim()); CoreClient.RegisterButtonEvent("inventory", new InventoryButtonEvent()); CoreClient.RegisterButtonEvent("reroll", new Reroll()); + CoreClient.RegisterButtonEvent("series", new SeriesEvent()); CoreClient.RegisterButtonEvent("trade", new TradeButtonEvent()); } } \ No newline at end of file -- 2.43.4 From 55b7f3fea9d9d0f1e39bcb0ec1481936684c858c Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Tue, 26 Mar 2024 11:39:06 +0000 Subject: [PATCH 4/4] Fix linting issues --- src/buttonEvents/Series.ts | 18 +++++++++--------- src/commands/series.ts | 23 +++++++++++------------ src/type/command.ts | 4 ++-- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/buttonEvents/Series.ts b/src/buttonEvents/Series.ts index 357a963..0d98bfb 100644 --- a/src/buttonEvents/Series.ts +++ b/src/buttonEvents/Series.ts @@ -8,15 +8,15 @@ export default class Series extends ButtonEvent { const subaction = interaction.customId.split(" ")[1]; switch(subaction) { - case "view": - await this.ViewSeries(interaction); - break; - case "list": - await this.ListSeries(interaction); - break; - default: - AppLogger.LogWarn("Commands/Series", `Subaction doesn't exist: ${subaction}`); - interaction.reply("Subaction doesn't exist."); + case "view": + await this.ViewSeries(interaction); + break; + case "list": + await this.ListSeries(interaction); + break; + default: + AppLogger.LogWarn("Commands/Series", `Subaction doesn't exist: ${subaction}`); + interaction.reply("Subaction doesn't exist."); } } diff --git a/src/commands/series.ts b/src/commands/series.ts index ee82b76..2122355 100644 --- a/src/commands/series.ts +++ b/src/commands/series.ts @@ -1,7 +1,6 @@ -import { CommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js"; +import { CommandInteraction, SlashCommandBuilder } from "discord.js"; import { Command } from "../type/command"; import { CoreClient } from "../client/client"; -import EmbedColours from "../constants/EmbedColours"; import AppLogger from "../client/appLogger"; import SeriesHelper from "../helpers/SeriesHelper"; @@ -24,22 +23,22 @@ export default class Series extends Command { .addSubcommand(x => x .setName("list") - .setDescription("List all series")); + .setDescription("List all series")) as SlashCommandBuilder; } public override async execute(interaction: CommandInteraction) { if (!interaction.isChatInputCommand()) return; switch (interaction.options.getSubcommand()) { - case "view": - await this.ViewSeries(interaction); - break; - case "list": - await this.ListSeries(interaction); - break; - default: - AppLogger.LogWarn("Commands/Series", `Subcommand doesn't exist: ${interaction.options.getSubcommand()}`); - await interaction.reply("Subcommand doesn't exist."); + case "view": + await this.ViewSeries(interaction); + break; + case "list": + await this.ListSeries(interaction); + break; + default: + AppLogger.LogWarn("Commands/Series", `Subcommand doesn't exist: ${interaction.options.getSubcommand()}`); + await interaction.reply("Subcommand doesn't exist."); } } diff --git a/src/type/command.ts b/src/type/command.ts index 409a4ca..20f5e3a 100644 --- a/src/type/command.ts +++ b/src/type/command.ts @@ -1,7 +1,7 @@ -import { CommandInteraction } from "discord.js"; +import { CommandInteraction, SlashCommandBuilder } from "discord.js"; export abstract class Command { - public CommandBuilder: any; + public CommandBuilder: Omit; abstract execute(interaction: CommandInteraction): Promise; } -- 2.43.4