feat: Introduce success and info embeds, add related user tracking to economy transactions, and refine trade interaction feedback and thread cleanup.

This commit is contained in:
syntaxbullet
2025-12-13 16:02:07 +01:00
parent f96d81f8a3
commit 7e9aa06556
6 changed files with 88 additions and 15 deletions

View File

@@ -27,3 +27,31 @@ export function createWarningEmbed(message: string, title: string = "Warning"):
.setColor(Colors.Yellow)
.setTimestamp();
}
/**
* Creates a standardized success embed.
* @param message The success message to display.
* @param title Optional title for the embed. Defaults to "Success".
* @returns An EmbedBuilder instance configured as a success.
*/
export function createSuccessEmbed(message: string, title: string = "Success"): EmbedBuilder {
return new EmbedBuilder()
.setTitle(`${title}`)
.setDescription(message)
.setColor(Colors.Green)
.setTimestamp();
}
/**
* Creates a standardized info embed.
* @param message The info message to display.
* @param title Optional title for the embed. Defaults to "Info".
* @returns An EmbedBuilder instance configured as info.
*/
export function createInfoEmbed(message: string, title: string = "Info"): EmbedBuilder {
return new EmbedBuilder()
.setTitle(` ${title}`)
.setDescription(message)
.setColor(Colors.Blue)
.setTimestamp();
}

View File

@@ -159,7 +159,7 @@ export const economyService = {
}
},
modifyUserBalance: async (id: string, amount: bigint, type: string, description: string, tx?: any) => {
modifyUserBalance: async (id: string, amount: bigint, type: string, description: string, relatedUserId?: string | null, tx?: any) => {
const execute = async (txFn: any) => {
if (amount < 0n) {
// Check sufficient funds if removing
@@ -180,6 +180,7 @@ export const economyService = {
await txFn.insert(transactions).values({
userId: BigInt(id),
relatedUserId: relatedUserId ? BigInt(relatedUserId) : null,
amount: amount,
type: type,
description: description,

View File

@@ -118,7 +118,7 @@ export const inventoryService = {
const totalPrice = item.price * quantity;
// Deduct Balance using economy service (passing tx ensures atomicity)
await economyService.modifyUserBalance(userId, -totalPrice, 'PURCHASE', `Bought ${quantity}x ${item.name}`, txFn);
await economyService.modifyUserBalance(userId, -totalPrice, 'PURCHASE', `Bought ${quantity}x ${item.name}`, null, txFn);
await inventoryService.addItem(userId, itemId, quantity, txFn);

View File

@@ -62,7 +62,7 @@ export const questService = {
if (rewards?.balance) {
const bal = BigInt(rewards.balance);
await economyService.modifyUserBalance(userId, bal, 'QUEST_REWARD', `Reward for quest ${questId}`, txFn);
await economyService.modifyUserBalance(userId, bal, 'QUEST_REWARD', `Reward for quest ${questId}`, null, txFn);
results.balance = bal;
}

View File

@@ -16,7 +16,7 @@ import {
} from "discord.js";
import { TradeService } from "./trade.service";
import { inventoryService } from "@/modules/inventory/inventory.service";
import { createErrorEmbed, createWarningEmbed } from "@lib/embeds";
import { createErrorEmbed, createWarningEmbed, createSuccessEmbed, createInfoEmbed } from "@lib/embeds";
const EMBED_COLOR = 0xFFD700; // Gold
@@ -61,18 +61,21 @@ export async function handleTradeInteraction(interaction: Interaction) {
}
async function handleCancel(interaction: ButtonInteraction | StringSelectMenuInteraction | ModalSubmitInteraction, threadId: string) {
const session = TradeService.getSession(threadId);
const user = interaction.user;
TradeService.endSession(threadId);
await interaction.reply({ content: "🛑 Trade cancelled. Deleting thread in 5 seconds..." });
setTimeout(async () => {
try {
await interaction.channel?.delete();
} catch (e) {
console.error("Failed to delete thread", e);
}
}, 5000);
await interaction.deferUpdate();
if (interaction.channel?.isThread()) {
const embed = createInfoEmbed(`Trade cancelled by ${user.username}.`, "Trade Cancelled");
await scheduleThreadCleanup(interaction.channel, "This thread will be deleted in 5 seconds.", 5000, embed);
}
}
async function handleLock(interaction: ButtonInteraction | StringSelectMenuInteraction | ModalSubmitInteraction, threadId: string) {
await interaction.deferUpdate();
const isLocked = TradeService.toggleLock(threadId, interaction.user.id);
await updateTradeDashboard(interaction, threadId);
@@ -214,12 +217,29 @@ export async function updateTradeDashboard(interaction: Interaction, threadId: s
.setTimestamp();
await updateDashboardMessage(interaction, { embeds: [embed], components: [] });
// Notify and Schedule Cleanup
if (interaction.channel?.isThread()) {
const successEmbed = createSuccessEmbed("Trade executed successfully. Items and funds have been transferred.", "Trade Complete");
await scheduleThreadCleanup(
interaction.channel,
`🎉 Trade successful! <@${session.userA.id}> <@${session.userB.id}>\nThis thread will be deleted in 10 seconds.`,
10000,
successEmbed
);
}
return;
} catch (e: any) {
const embed = createErrorEmbed(e.message, "Trade Failed");
console.error("Trade Execution Error:", e);
const errorEmbed = createErrorEmbed(e.message, "Trade Failed");
if (interaction.channel && (interaction.channel.isThread() || interaction.channel instanceof TextChannel)) {
await interaction.channel.send({ embeds: [embed] });
if (interaction.channel?.isThread()) {
await scheduleThreadCleanup(
interaction.channel,
"❌ Trade failed due to an error. This thread will be deleted in 10 seconds.",
10000,
errorEmbed
);
}
return;
}
@@ -291,3 +311,25 @@ function formatOffer(participant: any) {
if (text === "") text = "*Empty Offer*";
return text;
}
async function scheduleThreadCleanup(channel: ThreadChannel | TextChannel, message: string, delayMs: number = 10000, embed?: EmbedBuilder) {
try {
const payload: any = { content: message };
if (embed) payload.embeds = [embed];
await channel.send(payload);
setTimeout(async () => {
try {
if (channel.isThread()) {
console.log(`Deleting thread: ${channel.id}`);
await channel.delete("Trade Session Ended");
}
} catch (e) {
console.error("Failed to delete thread", e);
}
}, delayMs);
} catch (e) {
console.error("Failed to send cleanup notification", e);
}
}

View File

@@ -144,6 +144,7 @@ export class TradeService {
-from.offer.money,
'TRADE_OUT',
`Trade with ${to.username} (Thread: ${threadId})`,
to.id,
tx
);
await economyService.modifyUserBalance(
@@ -151,6 +152,7 @@ export class TradeService {
from.offer.money,
'TRADE_IN',
`Trade with ${from.username} (Thread: ${threadId})`,
from.id,
tx
);
}