- Updated ticket command and interaction responses to utilize the new `ephemeral()` function for consistent ephemeral message handling. - Enhanced error handling for member fetching in ticket interactions, ensuring proper responses when members are not found. - Improved localization for new error messages related to member presence in ticket commands. - Documented changes in phase tracking to reflect updates in ticket interaction responses.
217 lines
6.3 KiB
TypeScript
217 lines
6.3 KiB
TypeScript
import type {
|
|
ButtonInteraction,
|
|
ChannelSelectMenuInteraction,
|
|
MentionableSelectMenuInteraction,
|
|
ModalSubmitInteraction,
|
|
RoleSelectMenuInteraction,
|
|
StringSelectMenuInteraction,
|
|
UserSelectMenuInteraction
|
|
} from 'discord.js';
|
|
import { decodeComponentCustomId, t, type DashboardModuleId } from '@nexumi/shared';
|
|
import { env } from './env.js';
|
|
import { getGuildLocale } from './i18n.js';
|
|
import { ephemeral } from './interaction-reply.js';
|
|
import { isModuleEnabled, moduleForComponent } from './module-gates.js';
|
|
import { isMaintenanceMode } from './presence.js';
|
|
import type { BotContext } from './types.js';
|
|
import {
|
|
handleModerationConfirmation,
|
|
isModerationConfirmation
|
|
} from './modules/moderation/confirmations.js';
|
|
import { handleVerificationButton } from './modules/verification/handlers.js';
|
|
import { isVerificationButton } from './modules/verification/service.js';
|
|
import {
|
|
handleBlackjackButton,
|
|
isBlackjackButton
|
|
} from './modules/economy/blackjack-buttons.js';
|
|
import {
|
|
handleEmbedModal,
|
|
handlePollButton,
|
|
isEmbedModal,
|
|
isPollButton
|
|
} from './modules/utility/index.js';
|
|
import { handleFunButton, isFunButton } from './modules/fun/index.js';
|
|
import { handleGiveawayButton, isGiveawayButton } from './modules/giveaways/index.js';
|
|
import { handleTicketInteraction, isTicketInteraction } from './modules/tickets/index.js';
|
|
import {
|
|
handleSelfRoleInteraction,
|
|
isSelfRoleInteraction
|
|
} from './modules/selfroles/index.js';
|
|
import {
|
|
handleSuggestionButton,
|
|
isSuggestionButton
|
|
} from './modules/suggestions/index.js';
|
|
import {
|
|
handleTempVoiceInteraction,
|
|
isTempVoiceInteraction,
|
|
isTempVoiceModal
|
|
} from './modules/tempvoice/index.js';
|
|
import { handleGuildBackupButton, isGuildBackupButton } from './modules/guildbackup/index.js';
|
|
import {
|
|
handleComponentsV2Interaction,
|
|
isComponentsV2Interaction
|
|
} from './modules/components-v2/index.js';
|
|
|
|
type AnyComponentInteraction =
|
|
| ButtonInteraction
|
|
| StringSelectMenuInteraction
|
|
| UserSelectMenuInteraction
|
|
| RoleSelectMenuInteraction
|
|
| ChannelSelectMenuInteraction
|
|
| MentionableSelectMenuInteraction
|
|
| ModalSubmitInteraction;
|
|
|
|
type InteractionHandler = {
|
|
match: (customId: string) => boolean;
|
|
handle: (interaction: AnyComponentInteraction, context: BotContext) => Promise<void>;
|
|
};
|
|
|
|
function asButton(interaction: AnyComponentInteraction): ButtonInteraction {
|
|
return interaction as ButtonInteraction;
|
|
}
|
|
|
|
function asModal(interaction: AnyComponentInteraction): ModalSubmitInteraction {
|
|
return interaction as ModalSubmitInteraction;
|
|
}
|
|
|
|
const handlers: InteractionHandler[] = [
|
|
{
|
|
match: isModerationConfirmation,
|
|
handle: (interaction, context) => handleModerationConfirmation(asButton(interaction), context)
|
|
},
|
|
{
|
|
match: isVerificationButton,
|
|
handle: (interaction, context) => handleVerificationButton(asButton(interaction), context)
|
|
},
|
|
{
|
|
match: isBlackjackButton,
|
|
handle: (interaction, context) => handleBlackjackButton(asButton(interaction), context)
|
|
},
|
|
{
|
|
match: isPollButton,
|
|
handle: (interaction, context) => handlePollButton(asButton(interaction), context)
|
|
},
|
|
{
|
|
match: isFunButton,
|
|
handle: (interaction, context) => handleFunButton(asButton(interaction), context)
|
|
},
|
|
{
|
|
match: isGiveawayButton,
|
|
handle: (interaction, context) => handleGiveawayButton(asButton(interaction), context)
|
|
},
|
|
{
|
|
match: isTicketInteraction,
|
|
handle: (interaction, context) =>
|
|
handleTicketInteraction(
|
|
interaction as Parameters<typeof handleTicketInteraction>[0],
|
|
context
|
|
)
|
|
},
|
|
{
|
|
match: isSelfRoleInteraction,
|
|
handle: (interaction, context) =>
|
|
handleSelfRoleInteraction(
|
|
interaction as Parameters<typeof handleSelfRoleInteraction>[0],
|
|
context
|
|
)
|
|
},
|
|
{
|
|
match: isSuggestionButton,
|
|
handle: (interaction, context) => handleSuggestionButton(asButton(interaction), context)
|
|
},
|
|
{
|
|
match: (customId) => isTempVoiceInteraction(customId) || isTempVoiceModal(customId),
|
|
handle: (interaction, context) =>
|
|
handleTempVoiceInteraction(
|
|
interaction as Parameters<typeof handleTempVoiceInteraction>[0],
|
|
context
|
|
)
|
|
},
|
|
{
|
|
match: isGuildBackupButton,
|
|
handle: (interaction, context) => handleGuildBackupButton(asButton(interaction), context)
|
|
},
|
|
{
|
|
match: isEmbedModal,
|
|
handle: (interaction, context) => handleEmbedModal(asModal(interaction), context)
|
|
},
|
|
{
|
|
match: isComponentsV2Interaction,
|
|
handle: (interaction, context) =>
|
|
handleComponentsV2Interaction(
|
|
interaction as Parameters<typeof handleComponentsV2Interaction>[0],
|
|
context
|
|
)
|
|
}
|
|
];
|
|
|
|
function moduleForComponentsV2(customId: string): DashboardModuleId | null {
|
|
const decoded = decodeComponentCustomId(customId);
|
|
if (!decoded) {
|
|
return null;
|
|
}
|
|
switch (decoded.source) {
|
|
case 'w':
|
|
return 'welcome';
|
|
case 't':
|
|
return 'tags';
|
|
case 's':
|
|
return 'scheduler';
|
|
case 'm':
|
|
return 'messages';
|
|
default:
|
|
return 'messages';
|
|
}
|
|
}
|
|
|
|
export async function routeComponentInteraction(
|
|
interaction: AnyComponentInteraction,
|
|
context: BotContext
|
|
): Promise<boolean> {
|
|
const customId = interaction.customId;
|
|
const locale = await getGuildLocale(context.prisma, interaction.guildId);
|
|
|
|
const maintenance = await isMaintenanceMode(context);
|
|
const ownerIds = env.OWNER_USER_IDS ?? [];
|
|
if (maintenance.enabled && !ownerIds.includes(interaction.user.id)) {
|
|
if (!interaction.replied && !interaction.deferred) {
|
|
await interaction.reply({
|
|
content: maintenance.message?.trim() || t(locale, 'generic.maintenance'),
|
|
...ephemeral()
|
|
});
|
|
}
|
|
return true;
|
|
}
|
|
|
|
let moduleId = moduleForComponent(customId);
|
|
if (!moduleId && isComponentsV2Interaction(customId)) {
|
|
moduleId = moduleForComponentsV2(customId);
|
|
}
|
|
|
|
if (moduleId && interaction.guildId) {
|
|
const enabled = await isModuleEnabled(
|
|
context.prisma,
|
|
context.redis,
|
|
interaction.guildId,
|
|
moduleId
|
|
);
|
|
if (!enabled) {
|
|
if (!interaction.replied && !interaction.deferred) {
|
|
await interaction.reply({
|
|
content: t(locale, 'generic.moduleDisabled'),
|
|
...ephemeral()
|
|
});
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
for (const handler of handlers) {
|
|
if (handler.match(customId)) {
|
|
await handler.handle(interaction, context);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|