GroupUp/src/buttons/event-creation/step1-gameSelection.ts

202 lines
8.2 KiB
TypeScript

import { ActionRow, ApplicationCommandFlags, ApplicationCommandTypes, Bot, ButtonStyles, Interaction, InteractionResponseTypes, MessageComponentTypes, TextStyles } from '../../../deps.ts';
import { infoColor1, somethingWentWrong } from '../../commandUtils.ts';
import { CommandDetails } from '../../types/commandTypes.ts';
import { Activities } from './activities.ts';
import {
addTokenToMap,
deleteTokenEarly,
generateActionRow,
generateMapId,
getNestedActivity,
idSeparator,
LfgEmbedIndexes,
lfgStartTimeName,
pathIdxEnder,
pathIdxSeparator,
selfDestructMessage,
tokenMap,
} from './utils.ts';
import utils from '../../utils.ts';
import { customId as createCustomActivityBtnId } from './step1a-openCustomModal.ts';
import { customId as finalizeEventBtnId } from './step2-finalize.ts';
import { monthsShort } from './dateTimeUtils.ts';
import { dbClient, queries } from '../../db.ts';
export const customId = 'gameSel';
export const eventTimeId = 'eventTime';
export const eventTimeZoneId = 'eventTimeZone';
export const eventDateId = 'eventDate';
export const eventDescriptionId = 'eventDescription';
const slashCommandName = 'create-event';
const details: CommandDetails = {
name: slashCommandName,
description: 'Creates a new event in this channel.',
type: ApplicationCommandTypes.ChatInput,
};
const customEventRow: ActionRow = {
type: MessageComponentTypes.ActionRow,
components: [{
type: MessageComponentTypes.Button,
style: ButtonStyles.Primary,
label: 'Create Custom Event',
customId: createCustomActivityBtnId,
}],
};
const execute = async (bot: Bot, interaction: Interaction) => {
if (interaction.data && (interaction.data.name === slashCommandName || interaction.data.customId) && interaction.member && interaction.guildId && interaction.channelId) {
// Light Telemetry
if (interaction.data.name === slashCommandName) {
dbClient.execute(queries.callIncCnt('cmd-gameSel')).catch((e) => utils.commonLoggers.dbError('step1-gameSelection.ts@cmd', 'call sproc INC_CNT on', e));
}
if (interaction.data.customId === customId) {
dbClient.execute(queries.callIncCnt('btn-gameSel')).catch((e) => utils.commonLoggers.dbError('step1-gameSelection.ts@btn', 'call sproc INC_CNT on', e));
}
// 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);
let prefillTime = '';
let prefillTimeZone = '';
let prefillDate = '';
let prefillDescription = '';
if (interaction.message && interaction.message.embeds[0].fields && interaction.message.embeds[0].fields[LfgEmbedIndexes.StartTime].name === lfgStartTimeName) {
let rawEventDateTime = interaction.message.embeds[0].fields[LfgEmbedIndexes.StartTime].value.split('\n')[0].split(' ');
const monthIdx = rawEventDateTime.findIndex((item) => monthsShort.includes(item.toUpperCase()));
prefillTime = rawEventDateTime.slice(0, monthIdx - 1).join(' ').trim();
prefillTimeZone = rawEventDateTime[monthIdx - 1].trim();
prefillDate = rawEventDateTime.slice(monthIdx).join(' ').trim();
prefillDescription = interaction.message.embeds[0].fields[LfgEmbedIndexes.Description].value.trim();
}
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
type: InteractionResponseTypes.Modal,
data: {
title: 'Enter Event Details',
customId: `${finalizeEventBtnId}${idSeparator}${finalizedIdxPath}`,
components: [{
type: MessageComponentTypes.ActionRow,
components: [{
type: MessageComponentTypes.InputText,
customId: eventTimeId,
label: 'Start Time:',
placeholder: 'Enter the start time as "HH:MM AM/PM"',
style: TextStyles.Short,
minLength: 1,
maxLength: 8,
value: prefillTime || undefined,
}],
}, {
type: MessageComponentTypes.ActionRow,
components: [{
type: MessageComponentTypes.InputText,
customId: eventTimeZoneId,
label: 'Time Zone:',
placeholder: 'Enter your time zone abbreviation (UTC±## also works)',
style: TextStyles.Short,
minLength: 2,
maxLength: 8,
value: prefillTimeZone || undefined,
}],
}, {
type: MessageComponentTypes.ActionRow,
components: [{
type: MessageComponentTypes.InputText,
customId: eventDateId,
label: 'Start Date:',
placeholder: 'Enter date as "MONTH/DAY/YEAR" or "Month Day, Year"',
style: TextStyles.Short,
minLength: 1,
maxLength: 20,
value: prefillDate || undefined,
}],
}, {
type: MessageComponentTypes.ActionRow,
components: [{
type: MessageComponentTypes.InputText,
customId: eventDescriptionId,
label: 'Description:',
placeholder: 'Briefly describe the event',
style: TextStyles.Paragraph,
required: false,
minLength: 0,
maxLength: 1000,
value: prefillDescription || undefined,
}],
}],
},
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1-gameSelection.ts:modal', interaction, e));
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 = '';
for (let i = 0; i < idxPath.length; i++) {
const idx = idxPath[i];
const idxPathCopy = [...idxPath].slice(0, i);
selectMenus.push(generateActionRow(currentBaseValue, getNestedActivity(idxPathCopy, Activities), selectMenuCustomId, idx));
selectMenuCustomId = `${selectMenuCustomId}$`;
currentBaseValue = `${currentBaseValue}${idx}${pathIdxSeparator}`;
}
selectMenus.push(customEventRow);
if (interaction.data.customId && interaction.data.customId.includes('$')) {
// Let discord know we didn't ignore the user
await bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
type: InteractionResponseTypes.DeferredUpdateMessage,
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1-gameSelection.ts:ping', interaction, e));
// Update the original game selector
await bot.helpers.editOriginalInteractionResponse(tokenMap.get(generateMapId(interaction.guildId, interaction.channelId, interaction.member.id))?.token || '', {
components: selectMenus,
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1-gameSelection.ts:edit', interaction, e));
} else {
// Delete old token entry if it exists
await deleteTokenEarly(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
// Store token for later use
addTokenToMap(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id);
// Send initial interaction
bot.helpers.sendInteractionResponse(interaction.id, interaction.token, {
type: InteractionResponseTypes.ChannelMessageWithSource,
data: {
embeds: [{
title: 'Please select a Game and Activity, or create a Custom Event.',
description: selfDestructMessage(new Date().getTime()),
color: infoColor1,
}],
flags: ApplicationCommandFlags.Ephemeral,
components: selectMenus,
},
}).catch((e: Error) => utils.commonLoggers.interactionSendError('step1-gameSelection.ts:init', interaction, e));
}
} else {
somethingWentWrong(bot, interaction, 'missingCoreValuesOnGameSel');
}
};
export const gameSelectionCommand = {
details,
execute,
};
export const gameSelectionButton = {
customId,
execute,
};