import { PermissionFlagsBits } from 'discord.js'; import { t, tf } from '@nexumi/shared'; import type { SlashCommand } from '../../types.js'; import { getGuildLocale } from '../../i18n.js'; import { requirePermission } from '../../permissions.js'; import { invitesCommandData, statsCommandData } from './command-definitions.js'; import { getInviteLeaderboard, getInviteStatsForUser } from './invites.js'; import { getStatsConfig, StatsSetupSchema, updateStatsChannels, upsertStatsConfig } from './service.js'; const statsCommand: SlashCommand = { data: statsCommandData, async execute(interaction, context) { const locale = await getGuildLocale(context.prisma, interaction.guildId); if (!interaction.inGuild()) { await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true }); return; } const guildId = interaction.guildId!; const sub = interaction.options.getSubcommand(); if (sub === 'setup') { if (!(await requirePermission(interaction, PermissionFlagsBits.ManageGuild, locale))) { return; } const membersChannel = interaction.options.getChannel('members_channel', true); const onlineChannel = interaction.options.getChannel('online_channel', true); const boostsChannel = interaction.options.getChannel('boosts_channel', true); const parsed = StatsSetupSchema.safeParse({ membersChannelId: membersChannel.id, onlineChannelId: onlineChannel.id, boostsChannelId: boostsChannel.id, membersTemplate: interaction.options.getString('members_template') ?? undefined, onlineTemplate: interaction.options.getString('online_template') ?? undefined, boostsTemplate: interaction.options.getString('boosts_template') ?? undefined }); if (!parsed.success) { await interaction.reply({ content: t(locale, 'stats.error.invalidSetup'), ephemeral: true }); return; } await upsertStatsConfig(context.prisma, guildId, parsed.data); await updateStatsChannels(context); await interaction.reply({ content: t(locale, 'stats.setup.done'), ephemeral: true }); return; } if (sub === 'refresh') { if (!(await requirePermission(interaction, PermissionFlagsBits.ManageGuild, locale))) { return; } const config = await getStatsConfig(context.prisma, guildId); if (!config?.enabled) { await interaction.reply({ content: t(locale, 'stats.notConfigured'), ephemeral: true }); return; } await updateStatsChannels(context); await interaction.reply({ content: t(locale, 'stats.refresh.done'), ephemeral: true }); } } }; const invitesCommand: SlashCommand = { data: invitesCommandData, async execute(interaction, context) { const locale = await getGuildLocale(context.prisma, interaction.guildId); if (!interaction.inGuild()) { await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true }); return; } const guildId = interaction.guildId!; const sub = interaction.options.getSubcommand(); if (sub === 'view') { const targetUser = interaction.options.getUser('user') ?? interaction.user; const stats = await getInviteStatsForUser(context.prisma, guildId, targetUser.id); if (!stats || stats.joins === 0) { await interaction.reply({ content: tf(locale, 'invites.view.empty', { user: `<@${targetUser.id}>` }), ephemeral: true }); return; } const net = stats.joins - stats.leaves - stats.fakes; await interaction.reply({ content: tf(locale, 'invites.view.result', { user: `<@${targetUser.id}>`, joins: stats.joins, leaves: stats.leaves, fakes: stats.fakes, net }), ephemeral: true }); return; } if (sub === 'leaderboard') { const entries = await getInviteLeaderboard(context.prisma, guildId, 10); if (entries.length === 0) { await interaction.reply({ content: t(locale, 'invites.leaderboard.empty'), ephemeral: true }); return; } const lines = entries.map((entry, index) => { const net = entry.joins - entry.leaves - entry.fakes; return tf(locale, 'invites.leaderboard.line', { rank: index + 1, user: `<@${entry.inviterId}>`, joins: entry.joins, leaves: entry.leaves, fakes: entry.fakes, net }); }); await interaction.reply({ content: `${t(locale, 'invites.leaderboard.header')}\n${lines.join('\n')}`, ephemeral: true }); } } }; export const statsCommands: SlashCommand[] = [statsCommand, invitesCommand];