AeThex-Bot-Master/aethex-bot/commands/schedule.js
sirpiglr 6f5c37959f Add new commands and improve existing ones for better user experience
Introduces new commands like `/automod`, `/giveaway`, `/rolepanel`, and `/schedule`. Enhances existing commands such as `/announce`, `/help`, `/leaderboard`, `/profile`, and `/serverinfo` with new features and improved embed designs. Updates welcome and goodbye listeners with rich embeds. Fixes a critical issue in the `/rolepanel` command regarding channel fetching. Adds interaction handling for role buttons and giveaway entries.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: eefee140-1301-4b6f-9439-2b0b883aa40a
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/qAaysIh
Replit-Helium-Checkpoint-Created: true
2025-12-08 07:24:49 +00:00

331 lines
10 KiB
JavaScript

const {
SlashCommandBuilder,
EmbedBuilder,
PermissionFlagsBits,
ChannelType
} = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('schedule')
.setDescription('Schedule a message to be sent later')
.setDefaultMemberPermissions(PermissionFlagsBits.ManageMessages)
.addSubcommand(sub =>
sub.setName('message')
.setDescription('Schedule a text message')
.addChannelOption(option =>
option.setName('channel')
.setDescription('Channel to send the message to')
.setRequired(true)
.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement)
)
.addStringOption(option =>
option.setName('content')
.setDescription('Message content')
.setRequired(true)
.setMaxLength(2000)
)
.addIntegerOption(option =>
option.setName('minutes')
.setDescription('Minutes from now')
.setRequired(true)
.setMinValue(1)
.setMaxValue(10080)
)
.addBooleanOption(option =>
option.setName('ping_everyone')
.setDescription('Ping @everyone')
.setRequired(false)
)
)
.addSubcommand(sub =>
sub.setName('embed')
.setDescription('Schedule an embed message')
.addChannelOption(option =>
option.setName('channel')
.setDescription('Channel to send the embed to')
.setRequired(true)
.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement)
)
.addStringOption(option =>
option.setName('title')
.setDescription('Embed title')
.setRequired(true)
.setMaxLength(256)
)
.addStringOption(option =>
option.setName('description')
.setDescription('Embed description')
.setRequired(true)
.setMaxLength(2000)
)
.addIntegerOption(option =>
option.setName('minutes')
.setDescription('Minutes from now')
.setRequired(true)
.setMinValue(1)
.setMaxValue(10080)
)
.addStringOption(option =>
option.setName('color')
.setDescription('Embed color')
.setRequired(false)
.addChoices(
{ name: '🟣 Purple', value: '7c3aed' },
{ name: '🟢 Green', value: '22c55e' },
{ name: '🔴 Red', value: 'ef4444' },
{ name: '🔵 Blue', value: '3b82f6' },
{ name: '🟡 Yellow', value: 'eab308' }
)
)
)
.addSubcommand(sub =>
sub.setName('list')
.setDescription('List scheduled messages')
)
.addSubcommand(sub =>
sub.setName('cancel')
.setDescription('Cancel a scheduled message')
.addStringOption(option =>
option.setName('id')
.setDescription('Scheduled message ID')
.setRequired(true)
)
),
async execute(interaction, supabase, client) {
const subcommand = interaction.options.getSubcommand();
if (subcommand === 'message') {
await handleMessage(interaction, supabase, client);
} else if (subcommand === 'embed') {
await handleEmbed(interaction, supabase, client);
} else if (subcommand === 'list') {
await handleList(interaction, supabase);
} else if (subcommand === 'cancel') {
await handleCancel(interaction, supabase, client);
}
},
};
async function handleMessage(interaction, supabase, client) {
await interaction.deferReply({ ephemeral: true });
const channel = interaction.options.getChannel('channel');
const content = interaction.options.getString('content');
const minutes = interaction.options.getInteger('minutes');
const pingEveryone = interaction.options.getBoolean('ping_everyone') || false;
const sendTime = Date.now() + (minutes * 60 * 1000);
const sendTimestamp = Math.floor(sendTime / 1000);
const scheduleId = `sched_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
try {
const scheduleData = {
id: scheduleId,
type: 'message',
channelId: channel.id,
content: pingEveryone ? `@everyone ${content}` : content,
sendTime: sendTime
};
client.scheduledMessages = client.scheduledMessages || new Map();
const timeout = setTimeout(() => sendScheduledMessage(scheduleId, client, supabase), minutes * 60 * 1000);
client.scheduledMessages.set(scheduleId, { ...scheduleData, timeout });
if (supabase) {
await supabase.from('scheduled_messages').insert({
id: scheduleId,
guild_id: interaction.guildId,
channel_id: channel.id,
type: 'message',
content: scheduleData.content,
send_time: new Date(sendTime).toISOString(),
created_by: interaction.user.id,
status: 'pending'
});
}
const embed = new EmbedBuilder()
.setColor(0x22c55e)
.setTitle('✅ Message Scheduled')
.setDescription(`Message will be sent to ${channel} <t:${sendTimestamp}:R>`)
.addFields(
{ name: 'ID', value: `\`${scheduleId}\``, inline: true },
{ name: 'Send Time', value: `<t:${sendTimestamp}:f>`, inline: true }
)
.setTimestamp();
await interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error('Schedule message error:', error);
await interaction.editReply({ content: 'Failed to schedule message.' });
}
}
async function handleEmbed(interaction, supabase, client) {
await interaction.deferReply({ ephemeral: true });
const channel = interaction.options.getChannel('channel');
const title = interaction.options.getString('title');
const description = interaction.options.getString('description');
const minutes = interaction.options.getInteger('minutes');
const color = interaction.options.getString('color') || '7c3aed';
const sendTime = Date.now() + (minutes * 60 * 1000);
const sendTimestamp = Math.floor(sendTime / 1000);
const scheduleId = `sched_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
try {
const embedData = {
title: title,
description: description,
color: parseInt(color, 16)
};
const scheduleData = {
id: scheduleId,
type: 'embed',
channelId: channel.id,
embedData: embedData,
sendTime: sendTime
};
client.scheduledMessages = client.scheduledMessages || new Map();
const timeout = setTimeout(() => sendScheduledMessage(scheduleId, client, supabase), minutes * 60 * 1000);
client.scheduledMessages.set(scheduleId, { ...scheduleData, timeout });
if (supabase) {
await supabase.from('scheduled_messages').insert({
id: scheduleId,
guild_id: interaction.guildId,
channel_id: channel.id,
type: 'embed',
embed_data: embedData,
send_time: new Date(sendTime).toISOString(),
created_by: interaction.user.id,
status: 'pending'
});
}
const embed = new EmbedBuilder()
.setColor(0x22c55e)
.setTitle('✅ Embed Scheduled')
.setDescription(`Embed will be sent to ${channel} <t:${sendTimestamp}:R>`)
.addFields(
{ name: 'ID', value: `\`${scheduleId}\``, inline: true },
{ name: 'Send Time', value: `<t:${sendTimestamp}:f>`, inline: true },
{ name: 'Embed Title', value: title, inline: false }
)
.setTimestamp();
await interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error('Schedule embed error:', error);
await interaction.editReply({ content: 'Failed to schedule embed.' });
}
}
async function handleList(interaction, supabase) {
await interaction.deferReply({ ephemeral: true });
if (!supabase) {
return interaction.editReply({ content: 'Database not available.' });
}
try {
const { data: scheduled, error } = await supabase
.from('scheduled_messages')
.select('*')
.eq('guild_id', interaction.guildId)
.eq('status', 'pending')
.order('send_time', { ascending: true });
if (error) throw error;
if (!scheduled || scheduled.length === 0) {
return interaction.editReply({ content: 'No scheduled messages.' });
}
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('📅 Scheduled Messages')
.setDescription(scheduled.map(s => {
const sendTimestamp = Math.floor(new Date(s.send_time).getTime() / 1000);
return `**ID:** \`${s.id}\`\nType: ${s.type}\nChannel: <#${s.channel_id}>\nSends: <t:${sendTimestamp}:R>`;
}).join('\n\n'))
.setFooter({ text: `${scheduled.length} scheduled` })
.setTimestamp();
await interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error('Schedule list error:', error);
await interaction.editReply({ content: 'Failed to fetch scheduled messages.' });
}
}
async function handleCancel(interaction, supabase, client) {
await interaction.deferReply({ ephemeral: true });
const scheduleId = interaction.options.getString('id');
try {
const scheduled = client.scheduledMessages?.get(scheduleId);
if (scheduled?.timeout) {
clearTimeout(scheduled.timeout);
client.scheduledMessages.delete(scheduleId);
}
if (supabase) {
await supabase
.from('scheduled_messages')
.update({ status: 'cancelled' })
.eq('id', scheduleId);
}
await interaction.editReply({ content: '✅ Scheduled message cancelled.' });
} catch (error) {
console.error('Schedule cancel error:', error);
await interaction.editReply({ content: 'Failed to cancel.' });
}
}
async function sendScheduledMessage(scheduleId, client, supabase) {
try {
const scheduled = client.scheduledMessages?.get(scheduleId);
if (!scheduled) return;
const channel = await client.channels.fetch(scheduled.channelId);
if (!channel) return;
if (scheduled.type === 'message') {
await channel.send(scheduled.content);
} else if (scheduled.type === 'embed') {
const embed = new EmbedBuilder()
.setColor(scheduled.embedData.color)
.setTitle(scheduled.embedData.title)
.setDescription(scheduled.embedData.description)
.setTimestamp();
await channel.send({ embeds: [embed] });
}
client.scheduledMessages.delete(scheduleId);
if (supabase) {
await supabase
.from('scheduled_messages')
.update({ status: 'sent' })
.eq('id', scheduleId);
}
} catch (error) {
console.error('Send scheduled message error:', error);
}
}