refactor: centralize custom interaction IDs into constants

Replace all hardcoded custom ID strings with module-level constants.
Each module now has *_CUSTOM_IDS in its types file, using functions
for dynamic IDs and PREFIX for startsWith matching.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
syntaxbullet
2026-04-02 11:36:35 +02:00
parent 70d59a091a
commit 3c256ba0b2
27 changed files with 238 additions and 132 deletions

View File

@@ -3,7 +3,7 @@ import { items } from "@db/schema";
import { DrizzleClient } from "@shared/db/DrizzleClient";
import type { ItemUsageData, ItemEffect } from "@shared/lib/types";
import { getItemWizardEmbed, getItemTypeSelection, getEffectTypeSelection, getDetailsModal, getEconomyModal, getVisualsModal, getEffectConfigModal } from "./item_wizard.view";
import type { DraftItem } from "./item_wizard.types";
import { ITEM_WIZARD_CUSTOM_IDS, type DraftItem } from "./item_wizard.types";
import { ItemType, EffectType } from "@shared/lib/constants";
// --- Types ---
@@ -41,13 +41,13 @@ export const renderWizard = (userId: string, isDraft = true) => {
export const handleItemWizardInteraction = async (interaction: Interaction) => {
// Only handle createitem interactions
if (!interaction.isButton() && !interaction.isStringSelectMenu() && !interaction.isModalSubmit()) return;
if (!interaction.customId.startsWith("createitem_")) return;
if (!interaction.customId.startsWith(ITEM_WIZARD_CUSTOM_IDS.PREFIX)) return;
const userId = interaction.user.id;
let draft = draftSession.get(userId);
// Special case for Cancel - doesn't need draft checks usually, but we want to clear it
if (interaction.customId === "createitem_cancel") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.CANCEL) {
draftSession.delete(userId);
if (interaction.isMessageComponent()) {
await interaction.update({ content: "❌ Item creation cancelled.", embeds: [], components: [] });
@@ -59,7 +59,7 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
if (!draft) {
if (interaction.isMessageComponent()) {
// Create one implicitly to prevent crashes, or warn user
if (interaction.customId === "createitem_start") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.START) {
// Allow start
} else {
await interaction.reply({ content: "⚠️ Session expired. Please run `/createitem` again.", ephemeral: true });
@@ -81,7 +81,7 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
// --- Routing ---
// 1. Details Modal
if (interaction.customId === "createitem_details") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.DETAILS) {
if (!interaction.isButton()) return;
const modal = getDetailsModal(draft);
await interaction.showModal(modal);
@@ -89,7 +89,7 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
}
// 2. Economy Modal
if (interaction.customId === "createitem_economy") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.ECONOMY) {
if (!interaction.isButton()) return;
const modal = getEconomyModal(draft);
await interaction.showModal(modal);
@@ -97,7 +97,7 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
}
// 3. Visuals Modal
if (interaction.customId === "createitem_visuals") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.VISUALS) {
if (!interaction.isButton()) return;
const modal = getVisualsModal(draft);
await interaction.showModal(modal);
@@ -105,14 +105,14 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
}
// 4. Type Toggle (Start Select Menu)
if (interaction.customId === "createitem_type_toggle") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.TYPE_TOGGLE) {
if (!interaction.isButton()) return;
const { components } = getItemTypeSelection();
await interaction.update({ components }); // Temporary view
return;
}
if (interaction.customId === "createitem_select_type") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.SELECT_TYPE) {
if (!interaction.isStringSelectMenu()) return;
const selected = interaction.values[0];
if (selected) {
@@ -125,14 +125,14 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
}
// 5. Add Effect Flow
if (interaction.customId === "createitem_addeffect_start") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.ADD_EFFECT_START) {
if (!interaction.isButton()) return;
const { components } = getEffectTypeSelection();
await interaction.update({ components });
return;
}
if (interaction.customId === "createitem_select_effect_type") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.SELECT_EFFECT_TYPE) {
if (!interaction.isStringSelectMenu()) return;
const effectType = interaction.values[0];
if (!effectType) return;
@@ -149,7 +149,7 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
}
// Toggle Consume
if (interaction.customId === "createitem_toggle_consume") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.TOGGLE_CONSUME) {
if (!interaction.isButton()) return;
draft.usageData.consume = !draft.usageData.consume;
const payload = renderWizard(userId);
@@ -159,43 +159,43 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
// 6. Handle Modal Submits
if (interaction.isModalSubmit()) {
if (interaction.customId === "createitem_modal_details") {
draft.name = interaction.fields.getTextInputValue("name");
draft.description = interaction.fields.getTextInputValue("desc");
draft.rarity = interaction.fields.getTextInputValue("rarity");
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.MODAL_DETAILS) {
draft.name = interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_NAME);
draft.description = interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_DESC);
draft.rarity = interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_RARITY);
}
else if (interaction.customId === "createitem_modal_economy") {
const price = parseInt(interaction.fields.getTextInputValue("price"));
else if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.MODAL_ECONOMY) {
const price = parseInt(interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_PRICE));
draft.price = isNaN(price) || price === 0 ? null : price;
}
else if (interaction.customId === "createitem_modal_visuals") {
draft.iconUrl = interaction.fields.getTextInputValue("icon");
draft.imageUrl = interaction.fields.getTextInputValue("image");
else if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.MODAL_VISUALS) {
draft.iconUrl = interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_ICON);
draft.imageUrl = interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_IMAGE);
}
else if (interaction.customId === "createitem_modal_effect") {
else if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.MODAL_EFFECT) {
const type = draft.pendingEffectType;
if (type) {
let effect: ItemEffect | null = null;
if (type === EffectType.ADD_XP || type === EffectType.ADD_BALANCE) {
const amount = parseInt(interaction.fields.getTextInputValue("amount"));
const amount = parseInt(interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_AMOUNT));
if (!isNaN(amount)) effect = { type: type as any, amount };
}
else if (type === EffectType.REPLY_MESSAGE) {
effect = { type: EffectType.REPLY_MESSAGE, message: interaction.fields.getTextInputValue("message") };
effect = { type: EffectType.REPLY_MESSAGE, message: interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_MESSAGE) };
}
else if (type === EffectType.XP_BOOST) {
const multiplier = parseFloat(interaction.fields.getTextInputValue("multiplier"));
const duration = parseInt(interaction.fields.getTextInputValue("duration"));
const multiplier = parseFloat(interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_MULTIPLIER));
const duration = parseInt(interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_DURATION));
if (!isNaN(multiplier) && !isNaN(duration)) effect = { type: EffectType.XP_BOOST, multiplier, durationSeconds: duration };
}
else if (type === EffectType.TEMP_ROLE) {
const roleId = interaction.fields.getTextInputValue("role_id");
const duration = parseInt(interaction.fields.getTextInputValue("duration"));
const roleId = interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_ROLE_ID);
const duration = parseInt(interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_DURATION));
if (roleId && !isNaN(duration)) effect = { type: EffectType.TEMP_ROLE, roleId: roleId, durationSeconds: duration };
}
else if (type === EffectType.COLOR_ROLE) {
const roleId = interaction.fields.getTextInputValue("role_id");
const roleId = interaction.fields.getTextInputValue(ITEM_WIZARD_CUSTOM_IDS.FIELD_ROLE_ID);
if (roleId) effect = { type: EffectType.COLOR_ROLE, roleId: roleId };
}
@@ -214,7 +214,7 @@ export const handleItemWizardInteraction = async (interaction: Interaction) => {
}
// 7. Save
if (interaction.customId === "createitem_save") {
if (interaction.customId === ITEM_WIZARD_CUSTOM_IDS.SAVE) {
if (!interaction.isButton()) return;
await interaction.deferUpdate(); // Prepare to save