Finish most of the create event
This commit is contained in:
parent
d5f0b08e08
commit
8c6a3749df
|
@ -1,5 +1,6 @@
|
|||
import { Button } from '../types/commandTypes.ts';
|
||||
import { createEventButton } from './event-creation/step1-gameSelection.ts';
|
||||
import { createCustomEventButton } from './event-creation/step1a-openCustomModal.ts';
|
||||
import { verifyCustomEventButton } from './event-creation/step1b-verifyCustomActivity.ts';
|
||||
|
||||
export const buttons: Array<Button> = [createEventButton, createCustomEventButton];
|
||||
export const buttons: Array<Button> = [createEventButton, createCustomEventButton, verifyCustomEventButton];
|
||||
|
|
|
@ -2,15 +2,12 @@ import { ActionRow, ApplicationCommandFlags, ApplicationCommandTypes, Bot, Butto
|
|||
import { infoColor1, somethingWentWrong } from '../../commandUtils.ts';
|
||||
import { CommandDetails } from '../../types/commandTypes.ts';
|
||||
import { Activities } from './activities.ts';
|
||||
import { deleteTokenEarly, generateActionRow, generateMapId, getNestedActivity, pathIdxEnder, pathIdxSeparator, tokenMap } from './utils.ts';
|
||||
import { deleteTokenEarly, generateActionRow, generateMapId, getNestedActivity, pathIdxEnder, idSeparator, pathIdxSeparator, tokenMap, addTokenToMap, tokenTimeoutMS, selfDestructMessage } from './utils.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { customId as createCustomActivityBtnId } from './step1a-openCustomModal.ts';
|
||||
|
||||
export const customId = 'gameSel';
|
||||
const slashCommandName = 'create-event';
|
||||
// Discord Interaction Tokens last 15 minutes, we will self kill after 14.5 minutes
|
||||
const tokenTimeoutS = (15 * 60) - 30;
|
||||
const tokenTimeoutMS = tokenTimeoutS * 1000;
|
||||
const details: CommandDetails = {
|
||||
name: slashCommandName,
|
||||
description: 'Creates a new event in this channel.',
|
||||
|
@ -21,26 +18,27 @@ const customEventRow: ActionRow = {
|
|||
type: MessageComponentTypes.ActionRow,
|
||||
components: [{
|
||||
type: MessageComponentTypes.Button,
|
||||
style: ButtonStyles.Primary,
|
||||
label: 'Create Custom Event',
|
||||
customId: createCustomActivityBtnId,
|
||||
style: ButtonStyles.Primary,
|
||||
}],
|
||||
};
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.data && (interaction.data.name === slashCommandName || interaction.data.customId) && interaction.member && interaction.guildId && interaction.channelId) {
|
||||
// Parse indexPath from the select value
|
||||
const rawIdxPath: Array<string> = interaction.data.values ? interaction.data.values[0].split(pathIdxSeparator) : [''];
|
||||
const idxPath: Array<number> = rawIdxPath.map((rawIdx) => rawIdx ? parseInt(rawIdx) : -1);
|
||||
|
||||
if (interaction.data.values && interaction.data.values[0] && interaction.data.values[0].endsWith(pathIdxEnder)) {
|
||||
// Check if we are done
|
||||
const customIdIdxPath = ((interaction.data.customId || '').substring((interaction.data.customId || '').indexOf(idSeparator) + 1) || '');
|
||||
const valuesIdxPath = (interaction.data?.values?.[0] || '');
|
||||
const strippedIdxPath = interaction.data.customId?.includes(idSeparator) ? customIdIdxPath : valuesIdxPath;
|
||||
const finalizedIdxPath = strippedIdxPath.substring(0, strippedIdxPath.lastIndexOf(pathIdxEnder));
|
||||
if ((interaction.data.customId?.includes(idSeparator) && interaction.data.customId.endsWith(pathIdxEnder)) || interaction.data?.values?.[0].endsWith(pathIdxEnder)) {
|
||||
// User selected activity, give them the details modal and delete the selectMenus
|
||||
await deleteTokenEarly(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.Modal,
|
||||
data: {
|
||||
title: 'Enter Event Details',
|
||||
customId: 'temp', //TODO: fix
|
||||
customId: `temp${idSeparator}${finalizedIdxPath}`, //TODO: finish
|
||||
components: [{
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
components: [{
|
||||
|
@ -48,6 +46,8 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
customId: 'eventTime',
|
||||
label: 'Start Time:',
|
||||
style: TextStyles.Short,
|
||||
minLength: 1,
|
||||
maxLength: 8,
|
||||
}],
|
||||
}, {
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
|
@ -56,6 +56,8 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
customId: 'eventTimeZone',
|
||||
label: 'Time Zone:',
|
||||
style: TextStyles.Short,
|
||||
minLength: 2,
|
||||
maxLength: 8,
|
||||
}],
|
||||
}, {
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
|
@ -64,6 +66,8 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
customId: 'eventDate',
|
||||
label: 'Start Date:',
|
||||
style: TextStyles.Short,
|
||||
minLength: 1,
|
||||
maxLength: 20,
|
||||
}],
|
||||
}, {
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
|
@ -73,6 +77,9 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
label: 'Description:',
|
||||
style: TextStyles.Paragraph,
|
||||
required: false,
|
||||
placeholder: finalizedIdxPath,
|
||||
minLength: 0,
|
||||
maxLength: 1000,
|
||||
}],
|
||||
}],
|
||||
},
|
||||
|
@ -80,6 +87,9 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// Parse indexPath from the select value
|
||||
const rawIdxPath: Array<string> = interaction.data.values ? interaction.data.values[0].split(pathIdxSeparator) : [''];
|
||||
const idxPath: Array<number> = rawIdxPath.map((rawIdx) => rawIdx ? parseInt(rawIdx) : -1);
|
||||
const selectMenus: Array<ActionRow> = [];
|
||||
let selectMenuCustomId = `${customId}$`;
|
||||
let currentBaseValue = '';
|
||||
|
@ -110,21 +120,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
await deleteTokenEarly(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
|
||||
|
||||
// Store token for later use
|
||||
tokenMap.set(generateMapId(interaction.guildId, interaction.channelId, interaction.member.id), {
|
||||
token: interaction.token,
|
||||
timeoutId: setTimeout(
|
||||
(guildId, channelId, userId) => {
|
||||
deleteTokenEarly(bot, interaction, guildId, channelId, userId);
|
||||
},
|
||||
tokenTimeoutMS,
|
||||
interaction.guildId,
|
||||
interaction.channelId,
|
||||
interaction.member.id,
|
||||
),
|
||||
});
|
||||
|
||||
// Calculate destruction time
|
||||
const destructTime = Math.floor((new Date().getTime() + tokenTimeoutMS) / 1000);
|
||||
addTokenToMap(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
|
||||
|
||||
// Send initial interaction
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
|
@ -132,7 +128,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
data: {
|
||||
embeds: [{
|
||||
title: 'Please select a Game and Activity, or create a Custom Event.',
|
||||
description: `Please note: This message will self destruct <t:${destructTime}:R> due to limits imposed by the Discord API.`,
|
||||
description: selfDestructMessage(new Date().getTime()),
|
||||
color: infoColor1,
|
||||
}],
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
|
@ -141,7 +137,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1-gameSelection.ts:init', interaction, e));
|
||||
}
|
||||
} else {
|
||||
somethingWentWrong;
|
||||
somethingWentWrong(bot, interaction, 'missingCoreValuesOnGameSel');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,28 +1,35 @@
|
|||
import { Bot, Interaction, InteractionResponseTypes, MessageComponentTypes, TextStyles } from '../../../deps.ts';
|
||||
import { deleteTokenEarly } from './utils.ts';
|
||||
import { deleteTokenEarly, idSeparator, pathIdxSeparator } from './utils.ts';
|
||||
import { customId as verifyCustomActivityId } from './step1b-verifyCustomActivity.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
||||
export const customId = 'createCustomActivity';
|
||||
export const customId = 'customAct';
|
||||
|
||||
export const activityTitleId = 'activityTitle';
|
||||
export const activitySubtitleId = 'activitySubtitle';
|
||||
export const activityMaxPlayersId = 'activityMaxPlayers';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction.member && interaction.guildId && interaction.channelId) {
|
||||
if (interaction.data?.customId && interaction.member && interaction.guildId && interaction.channelId) {
|
||||
const [actTitle, actSubtitle, activityMaxPlayers] = (interaction.data.customId.split(idSeparator)[1] || '').split(pathIdxSeparator);
|
||||
|
||||
await deleteTokenEarly(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.Modal,
|
||||
data: {
|
||||
title: 'Create Custom Activity',
|
||||
customId: 'temp', //TODO: fix
|
||||
customId: verifyCustomActivityId,
|
||||
components: [{
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
components: [{
|
||||
type: MessageComponentTypes.InputText,
|
||||
customId: activityTitleId,
|
||||
label: 'Activity Title:',
|
||||
placeholder: 'The name of the game or event.',
|
||||
style: TextStyles.Short,
|
||||
minLength: 1,
|
||||
maxLength: 35,
|
||||
value: actTitle || undefined,
|
||||
}],
|
||||
}, {
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
|
@ -30,15 +37,23 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
type: MessageComponentTypes.InputText,
|
||||
customId: activitySubtitleId,
|
||||
label: 'Activity Subtitle:',
|
||||
placeholder: 'The specific activity within the game or event.',
|
||||
style: TextStyles.Short,
|
||||
minLength: 1,
|
||||
maxLength: 50,
|
||||
value: actSubtitle || undefined,
|
||||
}],
|
||||
}, {
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
components: [{
|
||||
type: MessageComponentTypes.InputText,
|
||||
customId: activityMaxPlayersId,
|
||||
label: 'Max Players:',
|
||||
label: 'Maximum Players:',
|
||||
placeholder: 'Please enter a number between 1 and 99.',
|
||||
style: TextStyles.Short,
|
||||
minLength: 1,
|
||||
maxLength: 2,
|
||||
value: activityMaxPlayers || undefined,
|
||||
}],
|
||||
}],
|
||||
},
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
import config from '../../../config.ts';
|
||||
import { Bot, Interaction, InteractionResponseTypes, MessageComponentTypes, ButtonStyles, ApplicationCommandFlags } from '../../../deps.ts';
|
||||
import { infoColor1, somethingWentWrong, failColor, safelyDismissMsg } from '../../commandUtils.ts';
|
||||
import { addTokenToMap, idSeparator, pathIdxSeparator, pathIdxEnder, selfDestructMessage } from './utils.ts';
|
||||
import { activityTitleId, activitySubtitleId, activityMaxPlayersId } from './step1a-openCustomModal.ts';
|
||||
import { customId as gameSelectionId } from './step1-gameSelection.ts';
|
||||
import { customId as openCustomModalId } from './step1a-openCustomModal.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
||||
export const customId = 'verifyCustomActivity';
|
||||
|
||||
const execute = async (bot: Bot, interaction: Interaction) => {
|
||||
if (interaction?.data?.components?.length && interaction.guildId && interaction.channelId && interaction.member) {
|
||||
// Parse out our data
|
||||
const tempDataMap: Map<string, string> = new Map();
|
||||
for (const row of interaction.data.components) {
|
||||
if (row.components?.[0]) {
|
||||
const textField = row.components[0];
|
||||
tempDataMap.set(textField.customId || 'missingCustomId', textField.value || 'missingValue');
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any pipe characters to avoid issues down the process
|
||||
const activityTitle = (tempDataMap.get(activityTitleId) || '').replace(/\|/g, '');
|
||||
const activitySubtitle = (tempDataMap.get(activitySubtitleId) || '').replace(/\|/g, '');
|
||||
const activityMaxPlayers = parseInt(tempDataMap.get(activityMaxPlayersId) || '0');
|
||||
if (!activityMaxPlayers || !activitySubtitle || !activityTitle) {
|
||||
// Verify fields exist
|
||||
somethingWentWrong(bot, interaction, `missingFieldFromCustomActivity@${activityTitle}|${activitySubtitle}|${activityMaxPlayers}$`);
|
||||
return;
|
||||
}
|
||||
if (activityMaxPlayers < 1 || activityMaxPlayers > 99) {
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
embeds: [{
|
||||
color: failColor,
|
||||
title: 'Invalid Max Member count!',
|
||||
description: `${config.name} parsed the max members as ${activityMaxPlayers}, which is outside of the allowed range. Please recreate this activity, but make sure the maximum player count is between 1 and 99.\n\n${safelyDismissMsg}`
|
||||
}],
|
||||
}
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1b-verifyCustomActivity.ts:invalidPlayer', interaction, e));
|
||||
return;
|
||||
}
|
||||
|
||||
addTokenToMap(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
|
||||
const idxPath = `${idSeparator}${activityTitle}${pathIdxSeparator}${activitySubtitle}${pathIdxSeparator}${activityMaxPlayers}`;
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
embeds: [{
|
||||
color: infoColor1,
|
||||
title: 'Please verify the following Custom Event details:',
|
||||
description: `Please note, pipe characters (\`|\`) are not allowed and will be automatically removed.\n\n${selfDestructMessage(new Date().getTime())}`,
|
||||
fields: [{
|
||||
name: 'Activity Title:',
|
||||
value: activityTitle,
|
||||
}, {
|
||||
name: 'Activity Subtitle:',
|
||||
value: activitySubtitle,
|
||||
}, {
|
||||
name: 'Maximum Players:',
|
||||
value: `${activityMaxPlayers}`,
|
||||
}],
|
||||
}],
|
||||
components: [{
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
components: [{
|
||||
type: MessageComponentTypes.Button,
|
||||
style: ButtonStyles.Success,
|
||||
label: 'Yup, looks great!',
|
||||
customId: `${gameSelectionId}${idxPath}${pathIdxEnder}`,
|
||||
},{
|
||||
type: MessageComponentTypes.Button,
|
||||
style: ButtonStyles.Danger,
|
||||
label: 'Nope, let me change something.',
|
||||
customId: `${openCustomModalId}${idxPath}`,
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1b-verifyCustomActivity.ts:message', interaction, e));
|
||||
} else {
|
||||
somethingWentWrong(bot, interaction, 'noDataFromCustomActivityModal');
|
||||
}
|
||||
};
|
||||
|
||||
export const verifyCustomEventButton = {
|
||||
customId,
|
||||
execute,
|
||||
};
|
|
@ -2,8 +2,13 @@ import { Activity } from './activities.ts';
|
|||
import { ActionRow, Bot, Interaction, MessageComponentTypes, SelectOption } from '../../../deps.ts';
|
||||
import utils from '../../utils.ts';
|
||||
|
||||
// Discord Interaction Tokens last 15 minutes, we will self kill after 14.5 minutes
|
||||
const tokenTimeoutS = (15 * 60) - 30;
|
||||
export const tokenTimeoutMS = tokenTimeoutS * 1000;
|
||||
export const idSeparator = '@';
|
||||
export const pathIdxSeparator = '|';
|
||||
export const pathIdxEnder = '&';
|
||||
export const selfDestructMessage = (currentTime: number) => `**Please note:** This message will self destruct <t:${Math.floor((currentTime + tokenTimeoutMS) / 1000)}:R> due to limits imposed by the Discord API.`
|
||||
|
||||
export const tokenMap: Map<string, {
|
||||
token: string;
|
||||
|
@ -38,6 +43,19 @@ export const generateActionRow = (baseValue: string, activities: Array<Activity>
|
|||
|
||||
export const generateMapId = (guildId: bigint, channelId: bigint, userId: bigint) => `${guildId}-${channelId}-${userId}`;
|
||||
|
||||
export const addTokenToMap = (bot: Bot, interaction: Interaction, guildId: bigint, channelId: bigint, userId: bigint) => tokenMap.set(generateMapId(guildId, channelId, userId), {
|
||||
token: interaction.token,
|
||||
timeoutId: setTimeout(
|
||||
(guildId, channelId, userId) => {
|
||||
deleteTokenEarly(bot, interaction, guildId, channelId, userId);
|
||||
},
|
||||
tokenTimeoutMS,
|
||||
guildId,
|
||||
channelId,
|
||||
userId,
|
||||
),
|
||||
});
|
||||
|
||||
export const deleteTokenEarly = async (bot: Bot, interaction: Interaction, guildId: bigint, channelId: bigint, userId: bigint) => {
|
||||
const tokenMapEntry = tokenMap.get(generateMapId(guildId, channelId, userId));
|
||||
if (tokenMapEntry && tokenMapEntry.token) {
|
||||
|
|
|
@ -9,6 +9,8 @@ export const successColor = 0x0f8108;
|
|||
export const infoColor1 = 0x313bf9;
|
||||
export const infoColor2 = 0x6805e9;
|
||||
|
||||
export const safelyDismissMsg = 'You may safely dismiss this message.'
|
||||
|
||||
export const getRandomStatus = (guildCount: number): string => {
|
||||
const statuses = [
|
||||
`Running V${config.version}`,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import config from '../../config.ts';
|
||||
import { ApplicationCommandFlags, ApplicationCommandTypes, Bot, Interaction, InteractionResponseTypes } from '../../deps.ts';
|
||||
import { failColor, somethingWentWrong, successColor } from '../commandUtils.ts';
|
||||
import { failColor, somethingWentWrong, successColor, safelyDismissMsg } from '../commandUtils.ts';
|
||||
import { dbClient, lfgChannelSettings, queries } from '../db.ts';
|
||||
import { CommandDetails } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
|
@ -53,7 +53,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
embeds: [{
|
||||
color: successColor,
|
||||
title: 'LFG Channel settings removed!',
|
||||
description: `${config.name} has finished removing the settings for this channel. You may safely dismiss this message.`,
|
||||
description: `${config.name} has finished removing the settings for this channel. ${safelyDismissMsg}`,
|
||||
}],
|
||||
},
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('delete.ts', interaction, e));
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
OverwriteTypes,
|
||||
sendMessage,
|
||||
} from '../../deps.ts';
|
||||
import { failColor, infoColor2, somethingWentWrong, successColor } from '../commandUtils.ts';
|
||||
import { failColor, infoColor2, somethingWentWrong, successColor, safelyDismissMsg } from '../commandUtils.ts';
|
||||
import { dbClient, lfgChannelSettings, queries } from '../db.ts';
|
||||
import { CommandDetails } from '../types/commandTypes.ts';
|
||||
import utils from '../utils.ts';
|
||||
|
@ -64,7 +64,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
|
||||
const setupOpts = interaction.data?.options?.[0];
|
||||
|
||||
if (setupOpts && setupOpts.name && interaction.channelId && interaction.guildId) {
|
||||
if (setupOpts?.name && interaction.channelId && interaction.guildId) {
|
||||
if (lfgChannelSettings.has(`${interaction.guildId}-${interaction.channelId}`)) {
|
||||
// Cannot setup a lfg channel that is already set up
|
||||
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
|
||||
|
@ -283,7 +283,7 @@ The Discord Slash Command system will ensure you provide all the required detail
|
|||
embeds: [{
|
||||
color: successColor,
|
||||
title: 'LFG Channel setup complete!',
|
||||
description: `${config.name} has finished setting up this channel. You may safely dismiss this message.`,
|
||||
description: `${config.name} has finished setting up this channel. ${safelyDismissMsg}`,
|
||||
}],
|
||||
},
|
||||
}).catch((e: Error) => utils.commonLoggers.interactionSendError('setup.ts', interaction, e));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Bot, BotWithCache, Interaction } from '../../deps.ts';
|
||||
import { buttons } from '../buttons/_index.ts';
|
||||
import { commands } from '../commands/_index.ts';
|
||||
import { idSeparator } from '../buttons/event-creation/utils.ts'
|
||||
|
||||
const commandNames: Array<string> = commands.map((command) => command.details.name);
|
||||
const buttonNames: Array<string> = buttons.map((button) => button.customId);
|
||||
|
@ -14,13 +15,14 @@ export const interactionCreate = (rawBot: Bot, interaction: Interaction) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const customId = interaction.data.customId ? interaction.data.customId.replace(/\$/g, '') : '';
|
||||
const tempCustomId = interaction.data.customId ? interaction.data.customId.replace(/\$/g, '') : '';
|
||||
const customId = tempCustomId.split(idSeparator)[0] || '';
|
||||
if (customId && buttonNames.includes(customId)) {
|
||||
const btnIdx = buttonNames.indexOf(customId);
|
||||
buttons[btnIdx].execute(bot, interaction);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('interaction NOT HANDLED');
|
||||
console.log('interaction NOT HANDLED', interaction);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue