const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require('discord.js'); module.exports = { data: new SlashCommandBuilder() .setName('announce') .setDescription('Send an announcement to all realms') .setDefaultMemberPermissions(PermissionFlagsBits.Administrator) .addStringOption(option => option.setName('title') .setDescription('Announcement title') .setRequired(true) .setMaxLength(256) ) .addStringOption(option => option.setName('message') .setDescription('Announcement message') .setRequired(true) .setMaxLength(2000) ) .addStringOption(option => option.setName('type') .setDescription('Announcement type (changes color and style)') .setRequired(false) .addChoices( { name: '📢 General (Purple)', value: 'general' }, { name: '🆕 Update (Green)', value: 'update' }, { name: '🎉 Event (Orange)', value: 'event' }, { name: '⚠️ Important (Red)', value: 'important' }, { name: '⭐ Highlight (Gold)', value: 'highlight' }, { name: '💡 Info (Blue)', value: 'info' } ) ) .addStringOption(option => option.setName('image') .setDescription('Image URL to include') .setRequired(false) ) .addBooleanOption(option => option.setName('ping') .setDescription('Ping @everyone with this announcement') .setRequired(false) ), async execute(interaction, supabase, client) { await interaction.deferReply({ ephemeral: true }); const title = interaction.options.getString('title'); const message = interaction.options.getString('message'); const type = interaction.options.getString('type') || 'general'; const imageUrl = interaction.options.getString('image'); const ping = interaction.options.getBoolean('ping') || false; const typeConfig = { general: { color: 0x7c3aed, emoji: '📢', label: 'Announcement' }, update: { color: 0x22c55e, emoji: '🆕', label: 'Update' }, event: { color: 0xf97316, emoji: '🎉', label: 'Event' }, important: { color: 0xef4444, emoji: '⚠️', label: 'Important' }, highlight: { color: 0xfbbf24, emoji: '⭐', label: 'Highlight' }, info: { color: 0x3b82f6, emoji: '💡', label: 'Info' } }; const config = typeConfig[type]; const embed = new EmbedBuilder() .setColor(config.color) .setAuthor({ name: `${config.emoji} ${config.label}`, iconURL: interaction.guild.iconURL({ size: 64 }) }) .setTitle(title) .setDescription(message) .setFooter({ text: `Announced by ${interaction.user.tag} • ${interaction.guild.name}`, iconURL: interaction.user.displayAvatarURL({ size: 32 }) }) .setTimestamp(); if (imageUrl) { embed.setImage(imageUrl); } const results = []; const REALM_GUILDS = client.REALM_GUILDS; for (const [realm, guildId] of Object.entries(REALM_GUILDS)) { if (!guildId) continue; const guild = client.guilds.cache.get(guildId); if (!guild) { results.push({ realm, status: 'offline', emoji: '⚫' }); continue; } try { const announcementChannel = guild.channels.cache.find( c => c.isTextBased() && !c.isThread() && !c.isVoiceBased() && (c.name.includes('announcement') || c.name.includes('general')) ); if (announcementChannel && announcementChannel.isTextBased()) { const content = ping ? '@everyone' : null; await announcementChannel.send({ content, embeds: [embed] }); results.push({ realm, status: 'sent', channel: announcementChannel.name, emoji: '✅' }); } else { results.push({ realm, status: 'no_channel', emoji: '⚠️' }); } } catch (error) { console.error(`Announce error for ${realm}:`, error); results.push({ realm, status: 'error', error: error.message, emoji: '❌' }); } } if (supabase) { try { await supabase.from('audit_logs').insert({ action: 'announce', user_id: interaction.user.id, username: interaction.user.tag, guild_id: interaction.guildId, details: { title, message, type, results }, }); } catch (e) { console.warn('Failed to log announcement:', e.message); } } const successCount = results.filter(r => r.status === 'sent').length; const failCount = results.filter(r => r.status !== 'sent' && r.status !== 'offline').length; const resultEmbed = new EmbedBuilder() .setColor(successCount > 0 ? 0x22c55e : 0xef4444) .setTitle(`${config.emoji} Announcement Results`) .setDescription( results.length > 0 ? results.map(r => `${r.emoji} **${capitalizeFirst(r.realm)}**: ${r.status}${r.channel ? ` (#${r.channel})` : ''}` ).join('\n') : 'No realms configured' ) .addFields({ name: '📊 Summary', value: `✅ Sent: ${successCount} | ⚠️ Failed: ${failCount} | ⚫ Offline: ${results.filter(r => r.status === 'offline').length}`, inline: false }) .setFooter({ text: `Type: ${config.label}` }) .setTimestamp(); await interaction.editReply({ embeds: [resultEmbed] }); }, }; function capitalizeFirst(str) { if (!str) return str; return str.charAt(0).toUpperCase() + str.slice(1); }