All around datetime parsing update, finalize step allows editing, lfg creator mostly there
This commit is contained in:
parent
4ddfd70655
commit
89bfce32f0
|
@ -15,6 +15,7 @@ export const config = {
|
|||
'link': { // Links to various sites
|
||||
'sourceCode': 'https://github.com/Burn-E99/GroupUp', // Link to the repository
|
||||
'supportServer': '', // Invite link to the Discord support server
|
||||
'addToCalendar': '', // Link to where the icsGenerator is hosted
|
||||
},
|
||||
'logChannel': 'the_log_channel', // Discord channel ID where the bot should put startup messages and other error messages needed
|
||||
'reportChannel': 'the_report_channel', // Discord channel ID where reports will be sent when using the built-in report command
|
||||
|
|
1
deps.ts
1
deps.ts
|
@ -41,6 +41,7 @@ export type {
|
|||
EventHandlers,
|
||||
Guild,
|
||||
Interaction,
|
||||
InteractionResponse,
|
||||
MakeRequired,
|
||||
Message,
|
||||
PermissionStrings,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const monthsLong: Array<string> = ['JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER'];
|
||||
const monthsShort: Array<string> = monthsLong.map((month) => month.slice(0, 3));
|
||||
export const monthsShort: Array<string> = monthsLong.map((month) => month.slice(0, 3));
|
||||
const tzMap: Map<string, string> = new Map([
|
||||
['CDT', '-05:00'],
|
||||
['CST', '-06:00'],
|
||||
|
@ -77,11 +77,15 @@ const parseEventTime = (preParsedEventTime: string): [string, string, string] =>
|
|||
parsedEventTimePeriod = '';
|
||||
}
|
||||
|
||||
if (!parsedEventTimePeriod && parsedEventTimeHours.length < 2) {
|
||||
parsedEventTimeHours = `0${parsedEventTimeHours}`;
|
||||
}
|
||||
|
||||
return [parsedEventTimeHours, parsedEventTimeMinutes, parsedEventTimePeriod];
|
||||
};
|
||||
|
||||
// Takes user input Time Zone and makes it actually usable
|
||||
const parseEventTimeZone = (preParsedEventTimeZone: string): string => {
|
||||
const parseEventTimeZone = (preParsedEventTimeZone: string): [string, string] => {
|
||||
if (shorthandUSTZ.includes(preParsedEventTimeZone)) {
|
||||
// Handle shorthand US timezones, adding S for standard time and D for Daylight Savings
|
||||
const today = new Date();
|
||||
|
@ -95,20 +99,20 @@ const parseEventTimeZone = (preParsedEventTimeZone: string): string => {
|
|||
}
|
||||
if (tzMap.has(preParsedEventTimeZone)) {
|
||||
// TZ is proper abbreviation, use our map to convert
|
||||
return tzMap.get(preParsedEventTimeZone) || 'how did we get here?';
|
||||
return [`UTC${tzMap.get(preParsedEventTimeZone)}`, preParsedEventTimeZone];
|
||||
} else {
|
||||
// Determine if user put in UTC4, which needs to be UTC+4
|
||||
let addPlusSign = false;
|
||||
if (!preParsedEventTimeZone.includes('+') || !preParsedEventTimeZone.includes('-')) {
|
||||
if (!preParsedEventTimeZone.includes('+') && !preParsedEventTimeZone.includes('-')) {
|
||||
addPlusSign = true;
|
||||
}
|
||||
// Determine if we need to prepend UTC/GMT, handle adding the + into the string
|
||||
if (!preParsedEventTimeZone.startsWith('UTC') || preParsedEventTimeZone.startsWith('GMT')) {
|
||||
if (!preParsedEventTimeZone.startsWith('UTC') && preParsedEventTimeZone.startsWith('GMT')) {
|
||||
preParsedEventTimeZone = `UTC${addPlusSign && '+'}${preParsedEventTimeZone}`;
|
||||
} else if (addPlusSign) {
|
||||
preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, 3)}+${preParsedEventTimeZone.slice(3)}`;
|
||||
}
|
||||
return preParsedEventTimeZone;
|
||||
return [preParsedEventTimeZone, preParsedEventTimeZone];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -135,8 +139,8 @@ const parseEventDate = (preParsedEventDate: string): [string, string, string] =>
|
|||
// Month and Day exist, so determine year and parse month/day
|
||||
parsedEventYear = (isNaN(parseInt(parsedEventYear)) ? today.getFullYear() : parseInt(parsedEventYear)).toString();
|
||||
parsedEventDay = parseInt(parsedEventDay).toString();
|
||||
if (!monthsLong.includes(parsedEventMonth) || !monthsShort.includes(parsedEventMonth)) {
|
||||
parsedEventMonth = parseInt(parsedEventMonth).toString();
|
||||
if (!monthsLong.includes(parsedEventMonth) && !monthsShort.includes(parsedEventMonth)) {
|
||||
parsedEventMonth = monthsShort[parseInt(parsedEventMonth) - 1];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,15 +148,20 @@ const parseEventDate = (preParsedEventDate: string): [string, string, string] =>
|
|||
};
|
||||
|
||||
// Take full raw Date/Time input and convert it to a proper Date
|
||||
export const getDateFromRawInput = (rawEventTime: string, rawEventTimeZone: string, rawEventDate: string): Date => {
|
||||
export const getDateFromRawInput = (rawEventTime: string, rawEventTimeZone: string, rawEventDate: string): [Date, string] => {
|
||||
// Verify/Set Time
|
||||
const [parsedEventTimeHours, parsedEventTimeMinutes, parsedEventTimePeriod] = parseEventTime(rawEventTime.replaceAll(':', '').toUpperCase());
|
||||
|
||||
// Verify/Set Time Zone
|
||||
const parsedEventTimeZone = parseEventTimeZone(rawEventTimeZone.replaceAll(' ', '').trim().toUpperCase());
|
||||
const [parsedEventTimeZone, userInputTimeZone] = parseEventTimeZone(rawEventTimeZone.replaceAll(' ', '').trim().toUpperCase());
|
||||
|
||||
// Verify/Set Date
|
||||
const [parsedEventYear, parsedEventMonth, parsedEventDay] = parseEventDate(rawEventDate.trim().toUpperCase());
|
||||
|
||||
return new Date(`${parsedEventMonth} ${parsedEventDay}, ${parsedEventYear} ${parsedEventTimeHours}:${parsedEventTimeMinutes} ${parsedEventTimePeriod} ${parsedEventTimeZone}`);
|
||||
return [
|
||||
new Date(`${parsedEventMonth} ${parsedEventDay}, ${parsedEventYear} ${parsedEventTimeHours}:${parsedEventTimeMinutes} ${parsedEventTimePeriod} ${parsedEventTimeZone}`),
|
||||
`${parsedEventTimeHours}${parsedEventTimePeriod ? ':' : ''}${parsedEventTimeMinutes} ${parsedEventTimePeriod} ${userInputTimeZone} ${parsedEventMonth.slice(0, 1)}${
|
||||
parsedEventMonth.slice(1, 3).toLowerCase()
|
||||
} ${parsedEventDay}, ${parsedEventYear}`,
|
||||
];
|
||||
};
|
||||
|
|
|
@ -2,10 +2,23 @@ import { ActionRow, ApplicationCommandFlags, ApplicationCommandTypes, Bot, Butto
|
|||
import { infoColor1, somethingWentWrong } from '../../commandUtils.ts';
|
||||
import { CommandDetails } from '../../types/commandTypes.ts';
|
||||
import { Activities } from './activities.ts';
|
||||
import { addTokenToMap, deleteTokenEarly, generateActionRow, generateMapId, getNestedActivity, idSeparator, pathIdxEnder, pathIdxSeparator, selfDestructMessage, tokenMap } from './utils.ts';
|
||||
import {
|
||||
addTokenToMap,
|
||||
deleteTokenEarly,
|
||||
generateActionRow,
|
||||
generateMapId,
|
||||
getNestedActivity,
|
||||
idSeparator,
|
||||
LfgEmbedIndexes,
|
||||
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';
|
||||
|
||||
export const customId = 'gameSel';
|
||||
export const eventTimeId = 'eventTime';
|
||||
|
@ -39,6 +52,20 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
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) {
|
||||
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 - 2).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: {
|
||||
|
@ -54,6 +81,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
style: TextStyles.Short,
|
||||
minLength: 1,
|
||||
maxLength: 8,
|
||||
value: prefillTime || undefined,
|
||||
}],
|
||||
}, {
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
|
@ -65,6 +93,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
style: TextStyles.Short,
|
||||
minLength: 2,
|
||||
maxLength: 8,
|
||||
value: prefillTimeZone || undefined,
|
||||
}],
|
||||
}, {
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
|
@ -76,6 +105,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
style: TextStyles.Short,
|
||||
minLength: 1,
|
||||
maxLength: 20,
|
||||
value: prefillDate || undefined,
|
||||
}],
|
||||
}, {
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
|
@ -88,6 +118,7 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
required: false,
|
||||
minLength: 0,
|
||||
maxLength: 1000,
|
||||
value: prefillDescription || undefined,
|
||||
}],
|
||||
}],
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Bot, Interaction, InteractionResponseTypes, MessageComponentTypes, TextStyles } from '../../../deps.ts';
|
||||
import { somethingWentWrong } from '../../commandUtils.ts';
|
||||
import { eventDateId, eventDescriptionId, eventTimeId, eventTimeZoneId } from './step1-gameSelection.ts';
|
||||
import { getFinalActivity, idSeparator, pathIdxSeparator } from './utils.ts';
|
||||
import { createLFGPost, getFinalActivity, idSeparator, pathIdxSeparator } from './utils.ts';
|
||||
import { Activities, Activity } from './activities.ts';
|
||||
import { getDateFromRawInput } from './dateTimeUtils.ts';
|
||||
|
||||
|
@ -51,9 +51,15 @@ const execute = async (bot: Bot, interaction: Interaction) => {
|
|||
}
|
||||
|
||||
// Get Date Object from user input
|
||||
const eventDateTime = getDateFromRawInput(rawEventTime, rawEventTimeZone, rawEventDate);
|
||||
const [eventDateTime, eventDateTimeStr] = getDateFromRawInput(rawEventTime, rawEventTimeZone, rawEventDate);
|
||||
|
||||
somethingWentWrong(bot, interaction, `TESTING@${rawEventTime}_${rawEventTimeZone}_${rawEventDate}`);
|
||||
bot.helpers.sendInteractionResponse(
|
||||
interaction.id,
|
||||
interaction.token,
|
||||
createLFGPost(category, activity, eventDateTime, eventDateTimeStr, eventDescription, interaction.member.nick || 'test', [], [], customIdIdxPath, true),
|
||||
);
|
||||
|
||||
// somethingWentWrong(bot, interaction, `TESTING@${rawEventTime}_${rawEventTimeZone}_${rawEventDate}`);
|
||||
} else {
|
||||
somethingWentWrong(bot, interaction, 'noDataFromEventDescriptionModal');
|
||||
}
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
import config from '../../../config.ts';
|
||||
import { Activity } from './activities.ts';
|
||||
import { ActionRow, Bot, Interaction, MessageComponentTypes, SelectOption } from '../../../deps.ts';
|
||||
import {
|
||||
ActionRow,
|
||||
ApplicationCommandFlags,
|
||||
Bot,
|
||||
ButtonComponent,
|
||||
ButtonStyles,
|
||||
Interaction,
|
||||
InteractionResponse,
|
||||
InteractionResponseTypes,
|
||||
MessageComponentTypes,
|
||||
SelectOption,
|
||||
} from '../../../deps.ts';
|
||||
import utils from '../../utils.ts';
|
||||
import { successColor } from '../../commandUtils.ts';
|
||||
import { LFGMember } from '../../types/commandTypes.ts';
|
||||
import { customId as gameSelCustomId } from './step1-gameSelection.ts';
|
||||
|
||||
// Discord Interaction Tokens last 15 minutes, we will self kill after 14.5 minutes
|
||||
const tokenTimeoutS = (15 * 60) - 30;
|
||||
|
@ -70,3 +85,119 @@ export const deleteTokenEarly = async (bot: Bot, interaction: Interaction, guild
|
|||
tokenMap.delete(generateMapId(guildId, channelId, userId));
|
||||
}
|
||||
};
|
||||
|
||||
const finalizeButtons = (idxPath: string): [ButtonComponent, ButtonComponent, ButtonComponent] => [{
|
||||
type: MessageComponentTypes.Button,
|
||||
label: 'Create Event',
|
||||
style: ButtonStyles.Success,
|
||||
customId: 'createEvent', // TODO: replace with proper id
|
||||
}, {
|
||||
type: MessageComponentTypes.Button,
|
||||
label: 'Create Whitelisted Event',
|
||||
style: ButtonStyles.Primary,
|
||||
customId: `createEvent${idSeparator}`, // TODO: replace with proper id
|
||||
}, {
|
||||
type: MessageComponentTypes.Button,
|
||||
label: 'Edit Event Details',
|
||||
style: ButtonStyles.Secondary,
|
||||
customId: `${gameSelCustomId}${idSeparator}${idxPath}${pathIdxEnder}`,
|
||||
}];
|
||||
|
||||
export const generateLFGButtons = (whitelist: boolean): [ButtonComponent, ButtonComponent, ButtonComponent, ButtonComponent, ButtonComponent] => [{
|
||||
type: MessageComponentTypes.Button,
|
||||
label: `${whitelist ? 'Request to ' : ''}Join`,
|
||||
style: ButtonStyles.Success,
|
||||
customId: `joinEvent${whitelist ? idSeparator : ''}`, // TODO: replace with proper id
|
||||
}, {
|
||||
type: MessageComponentTypes.Button,
|
||||
label: `Join as Alternate`,
|
||||
style: ButtonStyles.Primary,
|
||||
customId: 'alternateEvent', // TODO: replace with proper id
|
||||
}, {
|
||||
type: MessageComponentTypes.Button,
|
||||
label: 'Leave',
|
||||
style: ButtonStyles.Danger,
|
||||
customId: 'leaveEvent', // TODO: replace with proper id
|
||||
}, {
|
||||
type: MessageComponentTypes.Button,
|
||||
label: '',
|
||||
style: ButtonStyles.Secondary,
|
||||
customId: 'editEvent', // TODO: replace with proper id
|
||||
emoji: {
|
||||
name: '✏️',
|
||||
},
|
||||
}, {
|
||||
type: MessageComponentTypes.Button,
|
||||
label: '',
|
||||
style: ButtonStyles.Secondary,
|
||||
customId: 'deleteEvent', // TODO: replace with proper id
|
||||
emoji: {
|
||||
name: '🗑️',
|
||||
},
|
||||
}];
|
||||
|
||||
export enum LfgEmbedIndexes {
|
||||
Activity,
|
||||
StartTime,
|
||||
ICSLink,
|
||||
Description,
|
||||
JoinedMembers,
|
||||
AlternateMembers,
|
||||
}
|
||||
export const createLFGPost = (
|
||||
category: string,
|
||||
activity: Activity,
|
||||
eventDateTime: Date,
|
||||
eventDateTimeStr: String,
|
||||
eventDescription: string,
|
||||
author: string,
|
||||
memberList: Array<LFGMember>,
|
||||
alternateList: Array<LFGMember>,
|
||||
idxPath: string,
|
||||
editing: boolean,
|
||||
whitelist = false,
|
||||
): InteractionResponse => {
|
||||
const icsDetails = `${category}: ${activity.name}`;
|
||||
return {
|
||||
type: InteractionResponseTypes.ChannelMessageWithSource,
|
||||
data: {
|
||||
flags: ApplicationCommandFlags.Ephemeral,
|
||||
content: editing ? 'Please verify the information below, then click on the $name button below' : 'test',
|
||||
embeds: [{
|
||||
color: successColor,
|
||||
fields: [{
|
||||
name: `${category}:`,
|
||||
value: activity.name,
|
||||
inline: true,
|
||||
}, {
|
||||
name: 'Start Time:',
|
||||
value: `${eventDateTimeStr}\n<t:${Math.floor(eventDateTime.getTime() / 1000)}:R>`,
|
||||
inline: true,
|
||||
}, {
|
||||
name: 'Add to Calendar:',
|
||||
value: `[Download ICS File](${config.links.addToCalendar}?t=${eventDateTime.getTime()}&n=${icsDetails.replaceAll(' ', '+')})`,
|
||||
inline: true,
|
||||
}, {
|
||||
name: 'Description:',
|
||||
value: eventDescription,
|
||||
}, {
|
||||
name: `Members Joined: ${memberList.length}/${activity.maxMembers}`,
|
||||
value: memberList.length ? memberList.map((member) => `${member.name} - <@${member.id}>`).join('\n') : 'None',
|
||||
inline: true,
|
||||
}, {
|
||||
name: 'Alternates:',
|
||||
value: alternateList.length ? alternateList.map((member) => `${member.name} - <@${member.id}>${member.joined ? ' *' : ''}`).join('\n') : 'None',
|
||||
inline: true,
|
||||
}],
|
||||
footer: {
|
||||
text: `Created by: ${author}`,
|
||||
},
|
||||
timestamp: eventDateTime.getTime(),
|
||||
}],
|
||||
components: [{
|
||||
type: MessageComponentTypes.ActionRow,
|
||||
components: editing ? finalizeButtons(idxPath) : generateLFGButtons(whitelist),
|
||||
}],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -31,3 +31,9 @@ export type DBGuildSettings = {
|
|||
managerRoleId: bigint;
|
||||
logChannelId: bigint;
|
||||
};
|
||||
|
||||
export type LFGMember = {
|
||||
id: bigint;
|
||||
name: string;
|
||||
joined?: boolean;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue