Reaction roles — react to get a role; remove the reaction to drop it.
reaction-roles-bot.js · 127 lines
Reaction roles — react to get a role; remove the reaction to drop it.
View on GitHubnode examples/reaction-roles-bot.js
javascript
/**
* Reaction roles — react to get a role; remove the reaction to drop it.
*
* Run `!roles` to post the picker (or set REACTION_ROLES_MESSAGE_ID).
*
* Usage:
* FLUXER_BOT_TOKEN=your_token node examples/reaction-roles-bot.js
*
* Configure ROLE_* env vars (or edit ROLE_EMOJI_MAP) with your guild's role IDs.
*
* @see https://fluxerjs.blstmo.com/guides/reactions/
*/
import { Client, Events, EmbedBuilder, parsePrefixCommand } from '@fluxerjs/core';
const ROLE_EMOJI_MAP = {
'🎮': process.env.ROLE_GAMING ?? 'ROLE_ID_FOR_GAMING',
'🎵': process.env.ROLE_MUSIC ?? 'ROLE_ID_FOR_MUSIC',
'📢': process.env.ROLE_ANNOUNCEMENTS ?? 'ROLE_ID_FOR_ANNOUNCEMENTS',
};
const PREFIX = '!';
const client = new Client({ intents: 0 });
let rolesMessageId = process.env.REACTION_ROLES_MESSAGE_ID ?? null;
function getRoleIdForEmoji(reaction) {
const key = reaction.emoji.id
? `${reaction.emoji.name}:${reaction.emoji.id}`
: reaction.emoji.name;
return ROLE_EMOJI_MAP[key] ?? ROLE_EMOJI_MAP[reaction.emoji.name];
}
async function handleReactionAdd({ reaction, user }) {
if (!reaction.guildId || reaction.messageId !== rolesMessageId) return;
if (user.bot) return;
const roleId = getRoleIdForEmoji(reaction);
if (!roleId || roleId.startsWith('ROLE_ID_')) return;
const guild = client.guilds.get(reaction.guildId);
if (!guild) return;
const member = guild.members.get(user.id) ?? (await guild.fetchMember(user.id).catch(() => null));
if (!member || member.roles.has(roleId)) return;
try {
await member.roles.add(roleId);
console.log(`[reaction-roles] Added role ${roleId} to user ${user.id}`);
} catch (err) {
console.error('[reaction-roles] Failed to add role:', err.message);
}
}
async function handleReactionRemove({ reaction, user }) {
if (!reaction.guildId || reaction.messageId !== rolesMessageId) return;
if (user.bot) return;
const roleId = getRoleIdForEmoji(reaction);
if (!roleId || roleId.startsWith('ROLE_ID_')) return;
const guild = client.guilds.get(reaction.guildId);
if (!guild) return;
const member = guild.members.get(user.id) ?? (await guild.fetchMember(user.id).catch(() => null));
if (!member || !member.roles.has(roleId)) return;
try {
await member.roles.remove(roleId);
console.log(`[reaction-roles] Removed role ${roleId} from user ${user.id}`);
} catch (err) {
console.error('[reaction-roles] Failed to remove role:', err.message);
}
}
client.on(Events.Ready, () => {
console.log(`Logged in as ${client.user?.username}`);
});
client.on(Events.MessageCreate, async (message) => {
if (message.author.bot || !message.content) return;
const parsed = parsePrefixCommand(message.content, PREFIX);
if (!parsed || parsed.command !== 'roles') return;
if (!message.guildId) {
await message.reply('Use this in a server channel.');
return;
}
const emojiList = Object.entries(ROLE_EMOJI_MAP)
.map(
([emoji, id]) => `${emoji} ${id.startsWith('ROLE_ID_') ? '(configure ROLE_EMOJI_MAP)' : ''}`,
)
.join('\n');
const embed = new EmbedBuilder()
.setTitle('Reaction Roles')
.setDescription(`React to get a role. Remove your reaction to remove the role.\n\n${emojiList}`)
.setColor(0x5865f2)
.setTimestamp();
const reply = await message.reply({ embeds: [embed] });
for (const emoji of Object.keys(ROLE_EMOJI_MAP)) {
await reply.react(emoji).catch((e) => console.warn('Could not add reaction', emoji, e.message));
}
rolesMessageId = reply.id;
console.log(
`[reaction-roles] Set roles message to ${reply.id}. Persist with REACTION_ROLES_MESSAGE_ID=${reply.id} REACTION_ROLES_CHANNEL_ID=${message.channelId}`,
);
});
client.on(Events.MessageReactionAdd, handleReactionAdd);
client.on(Events.MessageReactionRemove, handleReactionRemove);
client.on(Events.Error, (err) => console.error('Client error:', err));
const token = process.env.FLUXER_BOT_TOKEN;
if (!token) {
console.error('Error: Set FLUXER_BOT_TOKEN');
process.exit(1);
}
try {
await client.login(token);
} catch (err) {
console.error('Login failed:', err);
process.exit(1);
}