GroupUp/src/lfgHandlers.ts

497 lines
14 KiB
TypeScript

import { ActionRow, ButtonComponent, DiscordButtonStyles, DiscordenoMember, EmbedField, log, LT } from '../deps.ts';
import { JoinLeaveType, UrlIds } from './lfgHandlers.d.ts';
import { BuildingLFG } from './mod.d.ts';
import { LFGActivities } from './games.ts';
import { determineTZ } from './timeUtils.ts';
import { lfgStepQuestions } from './constantCmds.ts';
import { jsonStringifyBig } from './utils.ts';
export const handleLFGStep = async (wipLFG: BuildingLFG, input: string): Promise<BuildingLFG> => {
const currentLFG = (wipLFG.lfgMsg.embeds[0] || { fields: undefined }).fields || [
{
name: '. . .',
value: '. . .',
inline: true,
},
{
name: 'Start Time:',
value: '. . .',
inline: true,
},
{
name: 'Add to Calendar:',
value: '. . .',
inline: true,
},
{
name: 'Description:',
value: '. . .',
inline: false,
},
{
name: `Members Joined: 0/?`,
value: 'None',
inline: true,
},
{
name: 'Alternates:',
value: 'None',
inline: true,
},
];
let nextQuestion = '';
const nextComponents: Array<ActionRow> = [];
let editFlag = true;
switch (wipLFG.step) {
case 'set_game': {
currentLFG[0].name = input.substr(0, 254);
if (Object.prototype.hasOwnProperty.call(LFGActivities, input)) {
nextQuestion = lfgStepQuestions.set_activity_with_button;
let tempObj = {};
Object.entries(LFGActivities).some((e) => {
if (e[0] === input) {
tempObj = e[1];
return true;
}
});
const activityButtons: Array<ButtonComponent> = Object.keys(tempObj).map((activity) => {
return {
type: 2,
label: activity,
customId: `building@set_activity#${activity}`,
style: DiscordButtonStyles.Primary,
};
});
const temp: Array<ActionRow['components']> = [];
activityButtons.forEach((btn, idx) => {
if (!temp[Math.floor(idx / 5)]) {
temp[Math.floor(idx / 5)] = [btn];
} else {
temp[Math.floor(idx / 5)].push(btn);
}
});
temp.forEach((btns) => {
if (btns.length && btns.length <= 5) {
nextComponents.push({
type: 1,
components: btns,
});
}
});
} else {
nextQuestion = lfgStepQuestions.set_activity_with_text;
}
wipLFG.step = 'set_activity';
break;
}
case 'set_activity': {
const game = currentLFG[0].name;
let tempObj;
Object.entries(LFGActivities).some((e) => {
if (e[0] === game) {
Object.entries(e[1]).some((f) => {
if (f[0] === input) {
tempObj = f[1];
return true;
}
});
return true;
}
});
currentLFG[0].name = `${game}:`;
currentLFG[0].value = input.substr(0, 1023);
if (typeof tempObj === 'number') {
// Activity
currentLFG[4].name = `Members Joined: ${currentLFG[4].value === 'None' ? 0 : currentLFG[4].value.split('\n').length}/${tempObj}`;
nextQuestion = wipLFG.editing ? lfgStepQuestions.set_done : lfgStepQuestions.set_time;
wipLFG.step = wipLFG.editing ? 'done' : 'set_time';
} else if (!tempObj) {
// Custom
nextQuestion = lfgStepQuestions.set_player_cnt;
wipLFG.step = 'set_player_cnt';
} else {
// Category
nextQuestion = lfgStepQuestions.set_activity_from_category;
currentLFG[0].name = game;
const activityButtons: Array<ButtonComponent> = Object.keys(tempObj).map((activity) => {
return {
type: 2,
label: activity,
customId: `building@set_activity_from_category#${activity}`,
style: DiscordButtonStyles.Primary,
};
});
const temp: Array<ActionRow['components']> = [];
activityButtons.forEach((btn, idx) => {
if (!temp[Math.floor(idx / 5)]) {
temp[Math.floor(idx / 5)] = [btn];
} else {
temp[Math.floor(idx / 5)].push(btn);
}
});
temp.forEach((btns) => {
if (btns.length && btns.length <= 5) {
nextComponents.push({
type: 1,
components: btns,
});
}
});
wipLFG.step = 'set_activity_from_category';
}
break;
}
case 'set_activity_from_category': {
const game = currentLFG[0].name;
const category = currentLFG[0].value;
let tempObj;
Object.entries(LFGActivities).some((e) => {
if (e[0] === game) {
Object.entries(e[1]).some((f) => {
if (f[0] === category) {
Object.entries(f[1]).some((g) => {
if (g[0] === input) {
tempObj = g[1];
return true;
}
});
return true;
}
});
return true;
}
});
currentLFG[0].name = `${game}:`;
currentLFG[0].value = input.substr(0, 1023);
if (tempObj) {
currentLFG[4].name = `Members Joined: ${currentLFG[4].value === 'None' ? 0 : currentLFG[4].value.split('\n').length}/${tempObj}`;
nextQuestion = wipLFG.editing ? lfgStepQuestions.set_done : lfgStepQuestions.set_time;
wipLFG.step = wipLFG.editing ? 'done' : 'set_time';
} else {
nextQuestion = lfgStepQuestions.set_player_cnt;
wipLFG.step = 'set_player_cnt';
}
break;
}
case 'set_player_cnt': {
if (parseInt(input)) {
currentLFG[4].name = `Members Joined: ${currentLFG[4].value === 'None' ? 0 : currentLFG[4].value.split('\n').length}/${Math.abs(parseInt(input)) || 1}`;
nextQuestion = wipLFG.editing ? lfgStepQuestions.set_done : lfgStepQuestions.set_time;
wipLFG.step = wipLFG.editing ? 'done' : 'set_time';
} else {
editFlag = false;
nextQuestion = `Input max members "${input}" is invalid, please make sure you are only entering a number.\n\n${lfgStepQuestions.set_player_cnt}`;
}
break;
}
case 'set_time': {
const today = new Date();
let lfgDate = `${today.getMonth() + 1}/${today.getDate()}`,
lfgTime = '',
lfgTZ = '',
lfgPeriod = '',
overrodeTZ = false;
input.split(' ').forEach((c) => {
if (c.includes('/')) {
lfgDate = c;
} else if (c.toLowerCase() === 'am' || c.toLowerCase() === 'pm') {
lfgPeriod = c.toLowerCase();
} else if (c.toLowerCase().includes('am') || c.toLowerCase().includes('pm')) {
lfgTime = c.substr(0, c.length - 2);
lfgPeriod = c.toLowerCase().includes('am') ? 'am' : 'pm';
} else if (c.includes(':')) {
lfgTime = c;
} else if (parseInt(c).toString() === (c.replace(/^0+/, '') || '0')) {
if (c.length === 4) {
if (parseInt(c) >= 1300) {
lfgTime = (parseInt(c) - 1200).toString();
lfgPeriod = 'pm';
} else if (parseInt(c) >= 1200) {
lfgTime = c;
lfgPeriod = 'pm';
} else {
lfgTime = c.startsWith('00') ? `12${c.substr(2)}` : c;
lfgPeriod = 'am';
}
const hourLen = lfgTime.length === 4 ? 2 : 1;
lfgTime = `${lfgTime.substr(0, hourLen)}:${lfgTime.substr(hourLen)}`;
} else {
lfgTime = c;
}
} else if (c.match(/^\d/)) {
const tzIdx = c.search(/[a-zA-Z]/);
lfgTime = c.substr(0, tzIdx);
[lfgTZ, overrodeTZ] = determineTZ(c.substr(tzIdx));
} else {
[lfgTZ, overrodeTZ] = determineTZ(c);
}
});
if (!lfgTZ) {
[lfgTZ, overrodeTZ] = determineTZ('ET');
}
if (!lfgTime.includes(':')) {
lfgTime += ':00';
}
if (!lfgPeriod) {
lfgPeriod = today.getHours() >= 12 ? 'pm' : 'am';
}
lfgPeriod = lfgPeriod.toUpperCase();
lfgTZ = lfgTZ.toUpperCase();
lfgDate = `${lfgDate.split('/')[0]}/${lfgDate.split('/')[1]}/${today.getFullYear()}`;
log(LT.LOG, `Date Time Debug | ${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}`);
const lfgDateTime = new Date(`${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}`);
lfgDate = `${lfgDate.split('/')[0]}/${lfgDate.split('/')[1]}`;
const lfgDateStr = `[${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}](https://groupup.eanm.dev/tz#${lfgDateTime.getTime()})`;
const icsDetails = `${currentLFG[0].name} ${currentLFG[0].value}`;
const icsStr = `[Download ICS File](https://groupup.eanm.dev/ics?t=${lfgDateTime.getTime()}&n=${icsDetails.replaceAll(' ', '+')})`;
currentLFG[1].name = 'Start Time (Click for Conversion):';
currentLFG[1].value = lfgDateStr.substr(0, 1023);
currentLFG[2].value = icsStr.substr(0, 1023);
if (isNaN(lfgDateTime.getTime())) {
nextQuestion =
`Input time "${input}" (parsed as "${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}") is invalid, please make sure you have the timezone set correctly.\n\n${lfgStepQuestions.set_time}`;
editFlag = false;
} else if (lfgDateTime.getTime() <= today.getTime()) {
nextQuestion =
`Input time "${input}" (parsed as "${lfgTime} ${lfgPeriod} ${lfgTZ} ${lfgDate}") is in the past, please make sure you are setting up the event to be in the future.\n\n${lfgStepQuestions.set_time}`;
editFlag = false;
} else {
nextQuestion = wipLFG.editing ? lfgStepQuestions.set_done : lfgStepQuestions.set_desc;
wipLFG.step = wipLFG.editing ? 'done' : 'set_desc';
}
break;
}
case 'set_desc': {
if (input === 'none') {
input = currentLFG[0].value;
}
currentLFG[3].value = input.substr(0, 1023);
nextQuestion = lfgStepQuestions.set_done;
wipLFG.step = 'done';
break;
}
default:
break;
}
try {
if (editFlag) {
wipLFG.lfgMsg = await wipLFG.lfgMsg.edit({
embeds: [{
fields: currentLFG,
}],
});
}
wipLFG.questionMsg = await wipLFG.questionMsg.edit({
content: nextQuestion,
components: nextComponents,
});
} catch (e) {
log(LT.WARN, `Failed to edit active builder | ${wipLFG.userId}-${wipLFG.channelId} | ${jsonStringifyBig(e)}`);
}
return wipLFG;
};
export const handleMemberJoin = (lfg: EmbedField[], member: DiscordenoMember, alternate: boolean): JoinLeaveType => {
let success = false;
let justFilled = false;
const userStr = `${member.username} - <@${member.id}>`;
const tempMembers = lfg[4].name.split(':')[1].split('/');
let currentMembers = parseInt(tempMembers[0]);
const maxMembers = parseInt(tempMembers[1]);
if (alternate && !lfg[5].value.includes(member.id.toString())) {
// remove from joined list
if (lfg[4].value.includes(member.id.toString())) {
const tempArr = lfg[4].value.split('\n');
const memberIdx = tempArr.findIndex((m) => m.includes(member.id.toString()));
tempArr.splice(memberIdx, 1);
lfg[4].value = tempArr.join('\n') || 'None';
if (currentMembers) {
currentMembers--;
}
lfg[4].name = `Members Joined: ${currentMembers}/${maxMembers}`;
}
if (lfg[5].value === 'None') {
lfg[5].value = userStr;
} else {
lfg[5].value += `\n${userStr}`;
}
success = true;
} else if (!alternate && currentMembers < maxMembers && !lfg[4].value.includes(member.id.toString())) {
// remove from alternate list
if (lfg[5].value.includes(member.id.toString())) {
const tempArr = lfg[5].value.split('\n');
const memberIdx = tempArr.findIndex((m) => m.includes(member.id.toString()));
tempArr.splice(memberIdx, 1);
lfg[5].value = tempArr.join('\n') || 'None';
}
if (lfg[4].value === 'None') {
lfg[4].value = userStr;
} else {
lfg[4].value += `\n${userStr}`;
}
currentMembers++;
justFilled = currentMembers === maxMembers;
lfg[4].name = `Members Joined: ${currentMembers}/${maxMembers}`;
success = true;
} else if (!alternate && currentMembers === maxMembers && !lfg[4].value.includes(member.id.toString())) {
// update user in alternate list to include the * to make them autojoin
if (lfg[5].value.includes(member.id.toString())) {
const tempArr = lfg[5].value.split('\n');
const memberIdx = tempArr.findIndex((m) => m.includes(member.id.toString()));
tempArr[memberIdx] = `${tempArr[memberIdx]} *`;
lfg[5].value = tempArr.join('\n');
} else {
if (lfg[5].value === 'None') {
lfg[5].value = `${userStr} *`;
} else {
lfg[5].value += `\n${userStr} *`;
}
success = true;
}
}
return {
embed: lfg,
success: success,
full: currentMembers === maxMembers,
justFilled: justFilled,
};
};
export const handleMemberLeave = (lfg: EmbedField[], member: DiscordenoMember): JoinLeaveType => {
let success = false;
const memberId = member.id.toString();
const tempMembers = lfg[4].name.split(':')[1].split('/');
let currentMembers = parseInt(tempMembers[0]);
const maxMembers = parseInt(tempMembers[1]);
if (lfg[4].value.includes(memberId)) {
const tempArr = lfg[4].value.split('\n');
const memberIdx = tempArr.findIndex((m) => m.includes(memberId));
tempArr.splice(memberIdx, 1);
lfg[4].value = tempArr.join('\n') || 'None';
if (lfg[5].value.includes('*')) {
// find first * user and move them to the joined list
const tempArr2 = lfg[5].value.split('\n');
const memberToMoveIdx = tempArr2.findIndex((m) => m.includes('*'));
let memberToMove = tempArr2[memberToMoveIdx];
memberToMove = memberToMove.substr(0, memberToMove.length - 2);
tempArr.push(memberToMove);
lfg[4].value = tempArr.join('\n') || 'None';
// Remove them from the alt list
tempArr2.splice(memberToMoveIdx, 1);
lfg[5].value = tempArr2.join('\n') || 'None';
} else {
// update count since no users were marked as *
if (currentMembers) {
currentMembers--;
}
lfg[4].name = `Members Joined: ${currentMembers}/${maxMembers}`;
}
success = true;
}
if (lfg[5].value.includes(memberId)) {
const tempArr = lfg[5].value.split('\n');
const memberIdx = tempArr.findIndex((m) => m.includes(memberId));
tempArr.splice(memberIdx, 1);
lfg[5].value = tempArr.join('\n') || 'None';
success = true;
}
return {
embed: lfg,
success: success,
full: currentMembers === maxMembers,
justFilled: false,
};
};
export const urlToIds = (url: string): UrlIds => {
const strIds = {
guildId: '',
channelId: '',
messageId: '',
};
url = url.toLowerCase();
[strIds.guildId, strIds.channelId, strIds.messageId] = url.substr(url.indexOf('channels') + 9).split('/');
return {
guildId: BigInt(strIds.guildId),
channelId: BigInt(strIds.channelId),
messageId: BigInt(strIds.messageId),
};
};