diff --git a/src/modules/terminal/terminal.service.ts b/src/modules/terminal/terminal.service.ts index 083070e..c736d62 100644 --- a/src/modules/terminal/terminal.service.ts +++ b/src/modules/terminal/terminal.service.ts @@ -1,4 +1,4 @@ -import { TextChannel, Message } from "discord.js"; +import { TextChannel, Message, ContainerBuilder, TextDisplayBuilder, SectionBuilder } from "discord.js"; import { AuroraClient } from "@/lib/BotClient"; import { DrizzleClient } from "@/lib/DrizzleClient"; import { users, transactions, lootdrops } from "@/db/schema"; @@ -67,8 +67,10 @@ export const terminalService = { const message = await channel.messages.fetch(terminalService.data.messageId); if (!message) return; - const content = await terminalService.buildMessage(); - await message.edit({ content: content, embeds: [] }); + const containers = await terminalService.buildMessage(); + // Using 'containers' property as per hypothetical new Discord.js API feature + // CASTING to any because TS might not know about 'containers' in MessageEditOptions yet if types aren't perfect + await message.edit({ content: "", containers: containers, embeds: [] } as any); } catch (error) { console.error("Failed to update terminal:", error); @@ -76,12 +78,12 @@ export const terminalService = { }, buildMessage: async () => { - // 1. Global Stats + // 1. Data Fetching const allUsers = await DrizzleClient.select().from(users); const totalUsers = allUsers.length; const totalWealth = allUsers.reduce((acc, u) => acc + (u.balance || 0n), 0n); - // 2. Leaderboards + // 2. Leaderboards Calculation const topLevels = [...allUsers].sort((a, b) => (b.level || 0) - (a.level || 0)).slice(0, 3); const topWealth = [...allUsers].sort((a, b) => Number(b.balance || 0n) - Number(a.balance || 0n)).slice(0, 3); @@ -93,7 +95,7 @@ export const terminalService = { const levelText = topLevels.map((u, i) => `> ${formatUser(u, i)} • Lvl ${u.level}`).join("\n") || "> *The sky is empty...*"; const wealthText = topWealth.map((u, i) => `> ${formatUser(u, i)} • ${u.balance} AU`).join("\n") || "> *The sky is empty...*"; - // 3. Lootdrops (Active/Recent) + // 3. Lootdrops Data const activeDrops = await DrizzleClient.query.lootdrops.findMany({ where: (lootdrops, { isNull }) => isNull(lootdrops.claimedBy), limit: 1, @@ -106,28 +108,47 @@ export const terminalService = { orderBy: desc(lootdrops.createdAt) }); - let phenomenaSection = ""; + // --- CONTAINER 1: Header --- + const headerContainer = new ContainerBuilder() + .setAccentColor(0x00ff99) + .addSectionComponents( + new SectionBuilder().addTextDisplayComponents( + new TextDisplayBuilder().setContent("# 🌌 AURORA OBSERVATORY"), + new TextDisplayBuilder().setContent("*Current Moon Phase: Waxing Crescent 🌒*") + ) + ); + + // --- CONTAINER 2: Observation Log --- + let phenomenaContent = ""; + if (activeDrops.length > 0 && activeDrops[0]) { const drop = activeDrops[0]; - phenomenaSection = ` -## 🌠 **SHOOTING STAR DETECTED** -> **Radiance**: \`${drop.rewardAmount} ${drop.currency}\` -> **Coordinates**: <#${drop.channelId}> -> **Impact**: `; + phenomenaContent = `\n**SHOOTING STAR DETECTED**\nRadiance: \`${drop.rewardAmount} ${drop.currency}\`\nCoordinates: <#${drop.channelId}>\nImpact: `; } else if (recentDrops.length > 0 && recentDrops[0]) { const drop = recentDrops[0]; const claimer = allUsers.find(u => u.id === drop.claimedBy); - phenomenaSection = ` -## 🌑 **RECENT CELESTIAL EVENTS** -> A star fell in <#${drop.channelId}> and was caught by **${claimer?.username || 'Unknown'}** -> **Yield**: \`${drop.rewardAmount} ${drop.currency}\``; - } else { - phenomenaSection = ` -## 🌑 **THE NIGHT IS QUIET** -> *Scanning the horizon for falling stars...*`; + phenomenaContent = `\n**RECENT EVENT**\nStar yielded \`${drop.rewardAmount} ${drop.currency}\` to **${claimer?.username || 'Unknown'}**`; } - // 4. Recent Activity + const logContainer = new ContainerBuilder() + .addSectionComponents( + new SectionBuilder().addTextDisplayComponents( + new TextDisplayBuilder().setContent("## 🔭 OBSERVATION LOG"), + new TextDisplayBuilder().setContent(`> **Stargazers**: \`${totalUsers}\`\n> **Astral Wealth**: \`${totalWealth.toLocaleString()} AU\`${phenomenaContent}`) + ) + ); + + // --- CONTAINER 3: Leaders --- + const leaderContainer = new ContainerBuilder() + .addSectionComponents( + new SectionBuilder().addTextDisplayComponents( + new TextDisplayBuilder().setContent("## ✨ CONSTELLATION LEADERS"), + new TextDisplayBuilder().setContent(`**Brightest Stars**\n${levelText}`), + new TextDisplayBuilder().setContent(`**Gilded Nebulas**\n${wealthText}`) + ) + ); + + // --- CONTAINER 4: Echoes --- const recentTx = await DrizzleClient.query.transactions.findMany({ limit: 5, orderBy: [desc(transactions.createdAt)] @@ -135,35 +156,22 @@ export const terminalService = { const activityLines = recentTx.map(tx => { const time = Math.floor(tx.createdAt!.getTime() / 1000); - let icon = "�"; - if (tx.type.includes("LOOT")) icon = "�"; + let icon = "💫"; + if (tx.type.includes("LOOT")) icon = "🌠"; if (tx.type.includes("GIFT")) icon = "🌕"; - const user = allUsers.find(u => u.id === tx.userId); - return ` ${icon} **${user?.username || 'Unknown'}**: ${tx.description}`; + return `\`[]\` ${icon} **${user?.username || 'Unknown'}**: ${tx.description}`; }); - const activityText = activityLines.join("\n") || "*Silence in the cosmos...*"; + const echoesContainer = new ContainerBuilder() + .addSectionComponents( + new SectionBuilder().addTextDisplayComponents( + new TextDisplayBuilder().setContent("## 📡 COSMIC ECHOES"), + new TextDisplayBuilder().setContent(activityLines.join("\n") || "Silence...") + ) + ); - // Construct the "Container" style message - return ` -# 🌌 **AURORA OBSERVATORY** -*Current Moon Phase: Waxing Crescent 🌒* -## 🔭 **OBSERVATION LOG** -> **Enrolled Stargazers**: \`${totalUsers}\` -> **Total Astral Wealth**: \`${totalWealth.toLocaleString()} AU\` -${phenomenaSection} - -## ✨ **CONSTELLATION LEADERS** -**Brightest Stars (Level)** -${levelText} - -**Gilded Nebulas (Wealth)** -${wealthText} - -## 📡 **COSMIC ECHOES** -${activityText} - `; + return [headerContainer, logContainer, leaderContainer, echoesContainer]; } };