forked from syntaxbullet/AuroraBot-discord
100 lines
3.7 KiB
TypeScript
100 lines
3.7 KiB
TypeScript
import { createCommand } from "@shared/lib/utils";
|
|
import {
|
|
SlashCommandBuilder,
|
|
ActionRowBuilder,
|
|
ButtonBuilder,
|
|
ButtonStyle,
|
|
type BaseGuildTextChannel,
|
|
PermissionFlagsBits,
|
|
MessageFlags
|
|
} from "discord.js";
|
|
import { inventoryService } from "@shared/modules/inventory/inventory.service";
|
|
import { createSuccessEmbed, createErrorEmbed, createBaseEmbed } from "@lib/embeds";
|
|
import { UserError } from "@/lib/errors";
|
|
import { items } from "@db/schema";
|
|
import { ilike, isNotNull, and } from "drizzle-orm";
|
|
import { DrizzleClient } from "@shared/db/DrizzleClient";
|
|
import { getShopListingMessage } from "@/modules/economy/shop.view";
|
|
|
|
export const listing = createCommand({
|
|
data: new SlashCommandBuilder()
|
|
.setName("listing")
|
|
.setDescription("Post an item listing in the channel for users to buy")
|
|
.addNumberOption(option =>
|
|
option.setName("item")
|
|
.setDescription("The item to list")
|
|
.setRequired(true)
|
|
.setAutocomplete(true)
|
|
)
|
|
.addChannelOption(option =>
|
|
option.setName("channel")
|
|
.setDescription("The channel to post the listing in (defaults to current)")
|
|
.setRequired(false)
|
|
)
|
|
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator),
|
|
execute: async (interaction) => {
|
|
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
|
|
|
const itemId = interaction.options.getNumber("item", true);
|
|
const targetChannel = (interaction.options.getChannel("channel") as BaseGuildTextChannel) || interaction.channel as BaseGuildTextChannel;
|
|
|
|
if (!targetChannel || !targetChannel.isSendable()) {
|
|
await interaction.editReply({ content: "", embeds: [createErrorEmbed("Target channel is invalid or not sendable.")] });
|
|
return;
|
|
}
|
|
|
|
const item = await inventoryService.getItem(itemId);
|
|
if (!item) {
|
|
await interaction.editReply({ content: "", embeds: [createErrorEmbed(`Item with ID ${itemId} not found.`)] });
|
|
return;
|
|
}
|
|
|
|
if (!item.price) {
|
|
await interaction.editReply({ content: "", embeds: [createErrorEmbed(`Item "${item.name}" is not for sale (no price set).`)] });
|
|
return;
|
|
}
|
|
|
|
const listingMessage = getShopListingMessage({
|
|
...item,
|
|
formattedPrice: `${item.price} 🪙`,
|
|
price: item.price
|
|
});
|
|
|
|
try {
|
|
await targetChannel.send(listingMessage);
|
|
await interaction.editReply({ content: `✅ Listing for **${item.name}** posted in ${targetChannel}.` });
|
|
} catch (error: any) {
|
|
if (error instanceof UserError) {
|
|
await interaction.reply({ embeds: [createErrorEmbed(error.message)], ephemeral: true });
|
|
} else {
|
|
console.error("Error creating listing:", error);
|
|
await interaction.reply({ embeds: [createErrorEmbed("An unexpected error occurred.")], ephemeral: true });
|
|
}
|
|
}
|
|
},
|
|
autocomplete: async (interaction) => {
|
|
const focusedValue = interaction.options.getFocused();
|
|
|
|
const results = await DrizzleClient.select({
|
|
id: items.id,
|
|
name: items.name,
|
|
price: items.price
|
|
})
|
|
.from(items)
|
|
.where(
|
|
and(
|
|
ilike(items.name, `%${focusedValue}%`),
|
|
isNotNull(items.price)
|
|
)
|
|
)
|
|
.limit(20);
|
|
|
|
await interaction.respond(
|
|
results.map(item => ({
|
|
name: `${item.name} (Price: ${item.price})`,
|
|
value: item.id
|
|
}))
|
|
);
|
|
}
|
|
});
|