src/utils/reaction/actions.ts
import {
getBroadcasts,
OriginalMessage,
} from '#main/utils/network/messageUtils.js';
import { CustomID } from '#utils/CustomID.js';
import db from '#utils/Db.js';
import { getEmojiId } from '#utils/Utils.js';
import {
ActionRowBuilder,
ButtonBuilder,
ButtonStyle,
ComponentType,
WebhookClient,
} from 'discord.js';
import type { ReactionArray } from '#types/Utils.d.ts';
import sortReactions from './sortReactions.js';
export const addReaction = (reactionArr: ReactionArray, userId: string, emoji: string): void => {
reactionArr[emoji] = reactionArr[emoji] || [];
reactionArr[emoji].push(userId);
};
export const removeReaction = (
reactionArr: ReactionArray,
userId: string,
emoji: string,
): ReactionArray => {
if (reactionArr[emoji]) {
reactionArr[emoji] = reactionArr[emoji].filter((id) => id !== userId);
if (reactionArr[emoji].length === 0) {
delete reactionArr[emoji];
}
}
return reactionArr;
};
const createReactionButtons = (
sortedReactions: [string, string[]][],
): ActionRowBuilder<ButtonBuilder> | null => {
if (sortedReactions.length === 0) return null;
const [mostReaction, users] = sortedReactions[0];
const reactionCount = users.length;
const mostReactionEmoji = getEmojiId(mostReaction);
if (!mostReactionEmoji) return null;
const reactionBtn = new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder()
.setCustomId(new CustomID().setIdentifier('reaction_', mostReaction).toString())
.setEmoji(mostReactionEmoji)
.setStyle(ButtonStyle.Secondary)
.setLabel(`${reactionCount}`),
);
const additionalReactionsCount = sortedReactions
.slice(1)
.filter(([, usrs]) => usrs.length > 0).length;
if (additionalReactionsCount > 0) {
reactionBtn.addComponents(
new ButtonBuilder()
.setCustomId(new CustomID().setIdentifier('reaction_', 'view_all').toString())
.setStyle(ButtonStyle.Secondary)
.setLabel(`+ ${additionalReactionsCount}`),
);
}
return reactionBtn;
};
const updateMessageComponents = async (
webhook: WebhookClient,
messageId: string,
threadId: string | undefined,
reactionBtn: ActionRowBuilder<ButtonBuilder> | null,
): Promise<void> => {
const message = await webhook.fetchMessage(messageId, { threadId }).catch(() => null);
if (!message) return;
const components =
message.components?.filter((row) => {
row.components = row.components.filter((component) => {
if (component.type !== ComponentType.Button) return true;
if (component.style !== ButtonStyle.Secondary) return true;
const custom_id = CustomID.parseCustomId(component.custom_id);
return custom_id.prefix !== 'reaction_' && custom_id.suffix !== 'view_all';
});
return row.components.length > 0;
}) || [];
if (reactionBtn) components.push(reactionBtn.toJSON());
await webhook.editMessage(messageId, { components, threadId }).catch(() => null);
};
export const updateReactions = async (
originalMessage: OriginalMessage,
reactions: { [key: string]: string[] },
): Promise<void> => {
const broadcastedMessages = Object.values(
await getBroadcasts(originalMessage.messageId, originalMessage.hubId),
);
const connections = await db.connectedList.findMany({
where: {
channelId: { in: broadcastedMessages.map((c) => c.channelId) },
connected: true,
},
});
const sortedReactions = sortReactions(reactions);
const reactionBtn = createReactionButtons(sortedReactions);
for (const connection of connections) {
const dbMsg = broadcastedMessages.find((e) => e.channelId === connection.channelId);
if (!dbMsg) continue;
await updateMessageComponents(
new WebhookClient({ url: connection.webhookURL }),
dbMsg.messageId,
connection.parentId ? connection.channelId : undefined,
reactionBtn,
);
}
};