diff --git a/src/buttons/event-creation/dateTimeUtils.ts b/src/buttons/event-creation/dateTimeUtils.ts index a1047ff..0eb7305 100644 --- a/src/buttons/event-creation/dateTimeUtils.ts +++ b/src/buttons/event-creation/dateTimeUtils.ts @@ -1,3 +1,6 @@ +import config from '../../../config.ts'; +import {editEventDetailsBtnName} from './utils.ts'; + const monthsLong: Array = ['JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER']; export const monthsShort: Array = monthsLong.map((month) => month.slice(0, 3)); const tzMap: Map = new Map([ @@ -52,7 +55,8 @@ const tzMap: Map = new Map([ ['CHST', '+10:00'], ['SST', '-11:00'], ]); -const shorthandUSTZ: Array = ['ET', 'CT', 'MT', 'PT']; +const shorthandUSTZ: Array = ['ET', 'CT', 'MT', 'PT', 'HT', 'AKT']; +const allUSTZ: Array = ['EST', 'CST', 'MST', 'PST', 'HST', 'AKST', 'EDT', 'CDT', 'MDT', 'PDT', 'HDT', 'AKDT']; // Takes user input Time and makes it actually usable const parseEventTime = (preParsedEventTime: string): [string, string, string] => { @@ -93,14 +97,31 @@ export const isDSTActive = (): boolean => { return today.getTimezoneOffset() < Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset()); }; +const editButtonMessage = `click \`${editEventDetailsBtnName}\` and change`; +const warningText = (incorrectTZ: string, correctTZ: string, newEvent: boolean) => + `⚠️⚠️⚠️ WARNING! Did you mean to enter \`${incorrectTZ}\` for the time zone? ⚠️⚠️⚠️\nCurrently (as of the posting of this message), Daylight Savings Time is ${isDSTActive() ? '' : 'not '}active in most of the United States. If DST is ${ + isDSTActive() ? '' : 'not ' + }in effect for you (and will be when this event is scheduled to happen), ${newEvent ? editButtonMessage : 'please dismiss this message and start over, using'} the time zone ${newEvent ? 'to ' : ''}\`${correctTZ}\`, or shorten it to \`${correctTZ.slice(0, -2)}T\` to let ${config.name} automatically use the correct time zone.\n\n`; + +const usTZDSTCheck = (timeZone: string, newEvent: boolean): string => { + if (allUSTZ.includes(timeZone)) { + if (isDSTActive() && timeZone.endsWith('ST')) { + return warningText(timeZone, `${timeZone.slice(0, -2)}DT`, newEvent); + } else if (!isDSTActive() && timeZone.endsWith('DT')) { + return warningText(timeZone, `${timeZone.slice(0, -2)}ST`, newEvent); + } + } + return ''; +}; + // Takes user input Time Zone and makes it actually usable const parseEventTimeZone = (preParsedEventTimeZone: string): [string, string] => { if (shorthandUSTZ.includes(preParsedEventTimeZone)) { // Handle shorthand US timezones, adding S for standard time and D for Daylight Savings if (isDSTActive()) { - preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, 1)}DT`; + preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, -1)}DT`; } else { - preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, 1)}ST`; + preParsedEventTimeZone = `${preParsedEventTimeZone.slice(0, -1)}ST`; } } if (tzMap.has(preParsedEventTimeZone)) { @@ -154,12 +175,13 @@ 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, string, boolean, boolean] => { +export const getDateFromRawInput = (rawEventTime: string, rawEventTimeZone: string, rawEventDate: string, newEvent: boolean): [Date, string, boolean, boolean, string] => { // Verify/Set Time const [parsedEventTimeHours, parsedEventTimeMinutes, parsedEventTimePeriod] = parseEventTime(rawEventTime.replaceAll(':', '').toUpperCase()); // Verify/Set Time Zone const [parsedEventTimeZone, userInputTimeZone] = parseEventTimeZone(rawEventTimeZone.replaceAll(' ', '').trim().toUpperCase()); + const usTZWarning = usTZDSTCheck(userInputTimeZone, newEvent); // Verify/Set Date const [parsedEventYear, parsedEventMonth, parsedEventDay] = parseEventDate(rawEventDate.trim().toUpperCase()); @@ -172,5 +194,6 @@ export const getDateFromRawInput = (rawEventTime: string, rawEventTimeZone: stri } ${parsedEventDay}, ${parsedEventYear}`, parsedDateTime.getTime() > new Date().getTime(), !isNaN(parsedDateTime.getTime()), + usTZWarning ]; }; diff --git a/src/buttons/event-creation/step2-finalize.ts b/src/buttons/event-creation/step2-finalize.ts index 120022d..c30d5e9 100644 --- a/src/buttons/event-creation/step2-finalize.ts +++ b/src/buttons/event-creation/step2-finalize.ts @@ -67,7 +67,7 @@ const execute = async (bot: Bot, interaction: Interaction) => { } // Get Date Object from user input - const [eventDateTime, eventDateTimeStr, eventInFuture, dateTimeValid] = getDateFromRawInput(rawEventTime, rawEventTimeZone, rawEventDate); + const [eventDateTime, eventDateTimeStr, eventInFuture, dateTimeValid, usTZWarning] = getDateFromRawInput(rawEventTime, rawEventTimeZone, rawEventDate, true); addTokenToMap(bot, interaction, interaction.guildId, interaction.channelId, interaction.member.id); bot.helpers.sendInteractionResponse( @@ -89,6 +89,7 @@ const execute = async (bot: Bot, interaction: Interaction) => { customIdIdxPath, eventInFuture, dateTimeValid, + usTZWarning, ), ).catch((e: Error) => utils.commonLoggers.interactionSendError('step2-finalize.ts', interaction, e)); } else { diff --git a/src/buttons/event-creation/utils.ts b/src/buttons/event-creation/utils.ts index 139f177..89b25c8 100644 --- a/src/buttons/event-creation/utils.ts +++ b/src/buttons/event-creation/utils.ts @@ -55,7 +55,7 @@ export const generateActionRow = (baseValue: string, activities: Array const createEventBtnName = 'Create Event'; const createWhitelistedBtnName = 'Create Whitelisted Event'; -const editEventDetailsBtnName = 'Edit Event Details'; +export const editEventDetailsBtnName = 'Edit Event Details'; export const invalidDateTimeStr = '`Invalid Date/Time`'; const finalizeButtons = (idxPath: string, eventInFuture: boolean): [ButtonComponent, ButtonComponent, ButtonComponent] | [ButtonComponent] => { const editButton: ButtonComponent = { @@ -129,6 +129,7 @@ export const createLFGPost = ( idxPath: string, eventInFuture: boolean, dateTimeValid: boolean, + usTZWarning: string, ): InteractionResponse => { const icsDetails = `${category}: ${activity.name}`; const dateTimePastFutureStr = dateTimeValid ? 'in the past' : 'with an invalid date/time'; @@ -138,7 +139,7 @@ export const createLFGPost = ( data: { flags: ApplicationCommandFlags.Ephemeral, content: eventInFuture - ? `🛑🛑🛑 HEY! ONE MORE THING! 🛑🛑🛑\n\nPlease verify the information below, then click on the \`${createEventBtnName}\` or \`${createWhitelistedBtnName}\` button, or change the event \`Date/Time\` or \`Description\` with the \`${editEventDetailsBtnName}\` button below. \n\n${ + ? `${usTZWarning}🛑🛑🛑 HEY! ONE MORE THING! 🛑🛑🛑\n\nPlease verify the information below, then click on the \`${createEventBtnName}\` or \`${createWhitelistedBtnName}\` button, or change the event \`Date/Time\` or \`Description\` with the \`${editEventDetailsBtnName}\` button below. \n\n${ selfDestructMessage(new Date().getTime()) }` : `You cannot create an event ${dateTimePastFutureStr}. Please change the event's \`Date/Time\` to be ${dateTimeValidStr} with the \`${editEventDetailsBtnName}\` button below.`, diff --git a/src/buttons/live-event/applyDateTime.ts b/src/buttons/live-event/applyDateTime.ts index e452385..a6f2c44 100644 --- a/src/buttons/live-event/applyDateTime.ts +++ b/src/buttons/live-event/applyDateTime.ts @@ -33,7 +33,7 @@ const execute = async (bot: Bot, interaction: Interaction) => { } // Get Date Object from user input - const [eventDateTime, eventDateTimeStr, eventInFuture, dateTimeValid] = getDateFromRawInput(newTime, newTimeZone, newDate); + const [eventDateTime, eventDateTimeStr, eventInFuture, dateTimeValid, usTZWarning] = getDateFromRawInput(newTime, newTimeZone, newDate, false); if (!eventInFuture || !dateTimeValid) { bot.helpers.sendInteractionResponse(interaction.id, interaction.token, { type: InteractionResponseTypes.ChannelMessageWithSource, @@ -70,7 +70,7 @@ const execute = async (bot: Bot, interaction: Interaction) => { type: InteractionResponseTypes.ChannelMessageWithSource, data: { flags: ApplicationCommandFlags.Ephemeral, - content: applyEditMessage(new Date().getTime()), + content: applyEditMessage(new Date().getTime(), usTZWarning), embeds: [eventMessage.embeds[0]], components: applyEditButtons(interaction.data.customId.split(idSeparator)[1] || ''), }, diff --git a/src/buttons/live-event/utils.ts b/src/buttons/live-event/utils.ts index 038babe..5691bd8 100644 --- a/src/buttons/live-event/utils.ts +++ b/src/buttons/live-event/utils.ts @@ -353,8 +353,8 @@ export const joinRequestResponseButtons = (disabled: boolean): ActionRow[] => [{ }]; export const applyEditButtonName = 'Apply Edit'; -export const applyEditMessage = (currentTime: number) => - `Please verify the updated event below, then click on the \`${applyEditButtonName}\` button. If this does not look right, please dismiss this message and start over.\n\n${ +export const applyEditMessage = (currentTime: number, usTZWarning: string) => + `${usTZWarning}Please verify the updated event below, then click on the \`${applyEditButtonName}\` button. If this does not look right, please dismiss this message and start over.\n\n${ selfDestructMessage(currentTime) }`; export const applyEditButtons = (idxPath: string): ActionRow[] => [{