refactor: add inventory view layer

Create inventory.view.ts with UI logic extracted from commands:
- getInventoryEmbed() for inventory display
- getItemUseResultEmbed() for item use results

Updated commands with proper type safety:
- inventory.ts: add null check, convert user.id to string
- use.ts: add null check, convert user.id to string

Improves separation of concerns and type safety.
This commit is contained in:
syntaxbullet
2025-12-24 22:08:51 +01:00
parent 2933eaeafc
commit 947bbc10d6
3 changed files with 57 additions and 14 deletions

View File

@@ -2,7 +2,8 @@ import { createCommand } from "@/lib/utils";
import { SlashCommandBuilder } from "discord.js"; import { SlashCommandBuilder } from "discord.js";
import { inventoryService } from "@/modules/inventory/inventory.service"; import { inventoryService } from "@/modules/inventory/inventory.service";
import { userService } from "@/modules/user/user.service"; import { userService } from "@/modules/user/user.service";
import { createWarningEmbed, createBaseEmbed } from "@lib/embeds"; import { createWarningEmbed } from "@lib/embeds";
import { getInventoryEmbed } from "@/modules/inventory/inventory.view";
export const inventory = createCommand({ export const inventory = createCommand({
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
@@ -24,18 +25,19 @@ export const inventory = createCommand({
} }
const user = await userService.getOrCreateUser(targetUser.id, targetUser.username); const user = await userService.getOrCreateUser(targetUser.id, targetUser.username);
const items = await inventoryService.getInventory(user.id); if (!user) {
await interaction.editReply({ embeds: [createWarningEmbed("Failed to load user data.", "Error")] });
return;
}
const items = await inventoryService.getInventory(user.id.toString());
if (!items || items.length === 0) { if (!items || items.length === 0) {
await interaction.editReply({ embeds: [createWarningEmbed("Inventory is empty.", `${user.username}'s Inventory`)] }); await interaction.editReply({ embeds: [createWarningEmbed("Inventory is empty.", `${user.username}'s Inventory`)] });
return; return;
} }
const description = items.map(entry => { const embed = getInventoryEmbed(items, user.username);
return `**${entry.item.name}** x${entry.quantity}`;
}).join("\n");
const embed = createBaseEmbed(`${user.username}'s Inventory`, description, "Blue");
await interaction.editReply({ embeds: [embed] }); await interaction.editReply({ embeds: [embed] });
} }

View File

@@ -2,7 +2,8 @@ import { createCommand } from "@/lib/utils";
import { SlashCommandBuilder } from "discord.js"; import { SlashCommandBuilder } from "discord.js";
import { inventoryService } from "@/modules/inventory/inventory.service"; import { inventoryService } from "@/modules/inventory/inventory.service";
import { userService } from "@/modules/user/user.service"; import { userService } from "@/modules/user/user.service";
import { createErrorEmbed, createSuccessEmbed } from "@lib/embeds"; import { createErrorEmbed } from "@lib/embeds";
import { getItemUseResultEmbed } from "@/modules/inventory/inventory.view";
import { inventory, items } from "@/db/schema"; import { inventory, items } from "@/db/schema";
import { eq, and, like } from "drizzle-orm"; import { eq, and, like } from "drizzle-orm";
import { DrizzleClient } from "@/lib/DrizzleClient"; import { DrizzleClient } from "@/lib/DrizzleClient";
@@ -25,9 +26,13 @@ export const use = createCommand({
const itemId = interaction.options.getNumber("item", true); const itemId = interaction.options.getNumber("item", true);
const user = await userService.getOrCreateUser(interaction.user.id, interaction.user.username); const user = await userService.getOrCreateUser(interaction.user.id, interaction.user.username);
if (!user) {
await interaction.editReply({ embeds: [createErrorEmbed("Failed to load user data.")] });
return;
}
try { try {
const result = await inventoryService.useItem(user.id, itemId); const result = await inventoryService.useItem(user.id.toString(), itemId);
const usageData = result.usageData; const usageData = result.usageData;
if (usageData) { if (usageData) {
@@ -53,11 +58,7 @@ export const use = createCommand({
} }
} }
const embed = createSuccessEmbed( const embed = getItemUseResultEmbed(result.results);
result.results.map(r => `${r}`).join("\n"),
`Used ${result.usageData.effects.length > 0 ? 'Item' : 'Item'}` // Generic title, improves below
);
embed.setTitle("Item Used!");
await interaction.editReply({ embeds: [embed] }); await interaction.editReply({ embeds: [embed] });

View File

@@ -0,0 +1,40 @@
import { EmbedBuilder } from "discord.js";
import type { ItemUsageData } from "@/lib/types";
/**
* Inventory entry with item details
*/
interface InventoryEntry {
quantity: bigint | null;
item: {
id: number;
name: string;
[key: string]: any;
};
}
/**
* Creates an embed displaying a user's inventory
*/
export function getInventoryEmbed(items: InventoryEntry[], username: string): EmbedBuilder {
const description = items.map(entry => {
return `**${entry.item.name}** x${entry.quantity}`;
}).join("\n");
return new EmbedBuilder()
.setTitle(`📦 ${username}'s Inventory`)
.setDescription(description)
.setColor(0x3498db); // Blue
}
/**
* Creates an embed showing the results of using an item
*/
export function getItemUseResultEmbed(results: string[], itemName?: string): EmbedBuilder {
const description = results.map(r => `${r}`).join("\n");
return new EmbedBuilder()
.setTitle("✅ Item Used!")
.setDescription(description)
.setColor(0x2ecc71); // Green/Success
}