From f75cc217e9b25ee7860761b6c06899ae10f8e9e4 Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Wed, 24 Dec 2025 11:44:43 +0100 Subject: [PATCH] refactor: extract further UI components into views --- src/commands/admin/listing.ts | 21 +++++++-------------- src/commands/economy/trade.ts | 25 ++++++------------------- src/modules/economy/shop.view.ts | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 src/modules/economy/shop.view.ts diff --git a/src/commands/admin/listing.ts b/src/commands/admin/listing.ts index bb293c3..bde00dc 100644 --- a/src/commands/admin/listing.ts +++ b/src/commands/admin/listing.ts @@ -14,6 +14,7 @@ import { UserError } from "@/lib/errors"; import { items } from "@/db/schema"; import { ilike, isNotNull, and } from "drizzle-orm"; import { DrizzleClient } from "@/lib/DrizzleClient"; +import { getShopListingMessage } from "@/modules/economy/shop.view"; export const listing = createCommand({ data: new SlashCommandBuilder() @@ -53,22 +54,14 @@ export const listing = createCommand({ return; } - const embed = createBaseEmbed(`Shop: ${item.name}`, item.description || "No description available.", "Green") - .addFields({ name: "Price", value: `${item.price} 🪙`, inline: true }) - .setThumbnail(item.iconUrl || null) - .setImage(item.imageUrl || null) - .setFooter({ text: "Click the button below to purchase instantly." }); - - const buyButton = new ButtonBuilder() - .setCustomId(`shop_buy_${item.id}`) - .setLabel(`Buy for ${item.price} 🪙`) - .setStyle(ButtonStyle.Success) - .setEmoji("🛒"); - - const actionRow = new ActionRowBuilder().addComponents(buyButton); + const listingMessage = getShopListingMessage({ + ...item, + formattedPrice: `${item.price} 🪙`, + price: item.price + }); try { - await targetChannel.send({ embeds: [embed], components: [actionRow] }); + await targetChannel.send(listingMessage); await interaction.editReply({ content: `✅ Listing for **${item.name}** posted in ${targetChannel}.` }); } catch (error: any) { if (error instanceof UserError) { diff --git a/src/commands/economy/trade.ts b/src/commands/economy/trade.ts index 158e931..17d5b4d 100644 --- a/src/commands/economy/trade.ts +++ b/src/commands/economy/trade.ts @@ -1,7 +1,8 @@ import { createCommand } from "@/lib/utils"; -import { SlashCommandBuilder, ChannelType, ActionRowBuilder, ButtonBuilder, ButtonStyle, ThreadAutoArchiveDuration, MessageFlags } from "discord.js"; +import { SlashCommandBuilder, ChannelType, ThreadAutoArchiveDuration, MessageFlags } from "discord.js"; import { TradeService } from "@/modules/trade/trade.service"; -import { createErrorEmbed, createWarningEmbed, createBaseEmbed } from "@lib/embeds"; +import { getTradeDashboard } from "@/modules/trade/trade.view"; +import { createErrorEmbed, createWarningEmbed } from "@lib/embeds"; export const trade = createCommand({ data: new SlashCommandBuilder() @@ -58,29 +59,15 @@ export const trade = createCommand({ } // Setup Session - TradeService.createSession(thread.id, + const session = TradeService.createSession(thread.id, { id: interaction.user.id, username: interaction.user.username }, { id: targetUser.id, username: targetUser.username } ); // Send Dashboard to Thread - const embed = createBaseEmbed("🤝 Trading Session", `Trade started between ${interaction.user} and ${targetUser}.\nUse the controls below to build your offer.`, 0xFFD700) - .addFields( - { name: interaction.user.username, value: "*Empty Offer*", inline: true }, - { name: targetUser.username, value: "*Empty Offer*", inline: true } - ) - .setFooter({ text: "Both parties must click Lock to confirm trade." }); + const dashboard = getTradeDashboard(session); - const row = new ActionRowBuilder() - .addComponents( - new ButtonBuilder().setCustomId('trade_add_item').setLabel('Add Item').setStyle(ButtonStyle.Secondary), - new ButtonBuilder().setCustomId('trade_add_money').setLabel('Add Money').setStyle(ButtonStyle.Success), - new ButtonBuilder().setCustomId('trade_remove_item').setLabel('Remove Item').setStyle(ButtonStyle.Secondary), - new ButtonBuilder().setCustomId('trade_lock').setLabel('Lock / Unlock').setStyle(ButtonStyle.Primary), - new ButtonBuilder().setCustomId('trade_cancel').setLabel('Cancel').setStyle(ButtonStyle.Danger), - ); - - await thread.send({ content: `${interaction.user} ${targetUser} Welcome to your trading session!`, embeds: [embed], components: [row] }); + await thread.send({ content: `${interaction.user} ${targetUser} Welcome to your trading session!`, ...dashboard }); // Update original reply await interaction.editReply({ content: `✅ Trade opened: <#${thread.id}>` }); diff --git a/src/modules/economy/shop.view.ts b/src/modules/economy/shop.view.ts new file mode 100644 index 0000000..3be9afe --- /dev/null +++ b/src/modules/economy/shop.view.ts @@ -0,0 +1,20 @@ +import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js"; +import { createBaseEmbed } from "@/lib/embeds"; + +export function getShopListingMessage(item: { id: number; name: string; description: string | null; formattedPrice: string; iconUrl: string | null; imageUrl: string | null; price: number | bigint }) { + const embed = createBaseEmbed(`Shop: ${item.name}`, item.description || "No description available.", "Green") + .addFields({ name: "Price", value: item.formattedPrice, inline: true }) + .setThumbnail(item.iconUrl || null) + .setImage(item.imageUrl || null) + .setFooter({ text: "Click the button below to purchase instantly." }); + + const buyButton = new ButtonBuilder() + .setCustomId(`shop_buy_${item.id}`) + .setLabel(`Buy for ${item.price} 🪙`) + .setStyle(ButtonStyle.Success) + .setEmoji("🛒"); + + const row = new ActionRowBuilder().addComponents(buyButton); + + return { embeds: [embed], components: [row] }; +}