feat: Reminders #44

Merged
Anri merged 54 commits from feat/reminders into main 2023-01-17 12:15:15 +01:00
9 changed files with 159 additions and 24 deletions
Showing only changes of commit 694d41a128 - Show all commits

View file

@ -1,5 +1,5 @@
import { SlashCommandBuilder } from '@discordjs/builders';
import { Client, ChatInputCommandInteraction } from 'discord.js';
import { ModalActionRowComponentBuilder, SlashCommandBuilder } from '@discordjs/builders';
import { Client, ChatInputCommandInteraction, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } from 'discord.js';
import { getLocalizations } from '../../utils/locales';
import { getFilename } from '../../utils/misc';
import { strToSeconds } from '../../utils/time';
@ -160,7 +160,6 @@ export default {
// plus user-friendly avec une interface (et en plus c'est
// nouveau et cool)
// eslint-disable-next-line no-case-declarations
let time = interaction.options.getString(loc_default?.get(`c_${filename}_sub1_opt1_name`) as string);
const message = interaction.options.getString(loc_default?.get(`c_${filename}_sub1_opt2_name`) as string);
let option = OptionReminder.Nothing;
@ -178,16 +177,36 @@ export default {
}
seconds = strToSeconds(time);
// Add the remind to the db
client.db.run('INSERT INTO reminder ( \
data, expiration_date, option_id, channel_id, creation_date, user_id, guild_id \
) VALUES ( ?, ?, ?, ?, ?, ?, ?);', [message, interaction.createdAt.getTime() + seconds, option.valueOf(), interaction.channelId, interaction.createdAt.getTime(), interaction.user.id, interaction.guildId]);
// Send confirmation to user
// TODO: local
await interaction.reply(`${option} - ${seconds}`);
} else {
// Boîte de dialogue
seconds = 0;
// GUI
// TODO: local
const modal = new ModalBuilder()
.setCustomId('reminderGUI')
.setTitle('LOC_reminder');
// TODO: local
const timeGUI = new TextInputBuilder()
.setCustomId('timeGUI')
.setLabel('LOC_time')
.setStyle(TextInputStyle.Short)
.setPlaceholder('1h')
.setRequired(true);
modal.addComponents(new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(timeGUI));
await interaction.showModal(modal);
// Response of the modal in /src/modals/misc/reminder
}
client.db.run('INSERT INTO reminder ( \
data, expiration_date, option_id, channel_id, creation_date, user_id, guild_id \
) VALUES ( ?, ?, ?, ?, ?, ?, ?);', [message, interaction.createdAt.getTime() + seconds, option.valueOf(), interaction.channelId, interaction.createdAt.getTime(), interaction.user.id, interaction.guildId]);
break;
}
// List reminders

View file

@ -3,16 +3,34 @@ import { getLocale } from '../../utils/locales';
/** https://discord.js.org/#/docs/discord.js/main/class/Client?scrollTo=e-interactionCreate */
export default (interaction: Interaction, client: Client) => {
if (interaction.type === InteractionType.ApplicationCommand) {
const command = client.commands.list.get(interaction.commandName);
if (!command) {
const loc = getLocale(client, interaction.locale);
return interaction.reply({
content: loc.get('e_interacreate_no_command'),
ephemeral: true,
});
const loc = getLocale(client, interaction.locale);
switch (interaction.type) {
case InteractionType.ApplicationCommand: {
const command = client.commands.list.get(interaction.commandName);
if (!command) {
return interaction.reply({
content: loc.get('e_interacreate_no_command'),
ephemeral: true,
});
}
return command.interaction(interaction, client);
}
return command.interaction(interaction, client);
case InteractionType.ModalSubmit: {
const modal = client.modals.list.get(interaction.customId);
if (!modal) {
return interaction.reply({
// TODO: locale
content: `can't find ${interaction.customId}`,
ephemeral: true,
});
}
return modal.interaction(interaction, client);
}
default:
break;
}
};

View file

@ -18,6 +18,7 @@ export default async (client: Client) => {
);
// Remove extension
// TODO: use utils functions
const event_type_ext = event_file.split('.');
const ext = event_type_ext.pop();
if (!(ext === 'js' || ext === 'ts')) {

View file

@ -1,5 +1,6 @@
import loadClient, { quit } from './utils/client';
import loadEvents from './events/loader';
import loadModals from './modals/loader';
import loadCommands from './commands/loader';
import { logStart } from './utils/misc';
@ -19,27 +20,37 @@ const run = async () => {
const client_name = 'Client';
await loadClient()
.then(async client => {
console.log(logStart(client_name, true));
// Events Discord.JS
const events_name = 'Events';
await loadEvents(client)
.then(() => console.log(logStart(events_name, true)))
.catch(() => {
.catch((err) => {
console.error(err);
throw logStart(events_name, false);
});
// Connect the bot to Discord.com
await client.login(client.config.token_discord);
// Modals Discord.JS
const modals_name = 'Modals';
await loadModals(client)
.then(() => console.log(logStart(modals_name, true)))
.catch((err) => {
console.error(err);
throw logStart(modals_name, false);
});
// Commands Slash Discord.JS
const commands_name = 'Commands';
await loadCommands(client)
.then(() => console.log(logStart(commands_name, true)))
.catch(() => {
.catch((err) => {
console.error(err);
throw logStart(commands_name, false);
});
console.log(logStart(client_name, true));
console.log(`Botanique "${client.user?.username}" v${client.config.version} started!`);
// ^C
@ -48,7 +59,8 @@ const run = async () => {
// Container force closed
process.on('SIGTERM', () => quit(client));
})
.catch(() => {
.catch((err) => {
console.error(err);
throw logStart(client_name, false);
});
};

36
src/modals/loader.ts Normal file
View file

@ -0,0 +1,36 @@
import { readdir } from 'fs/promises';
import { removeExtension } from '../utils/misc';
import { Client } from 'discord.js';
export default async (client: Client) => {
// Dossier des modals
const modals_categories = (await readdir(__dirname))
.filter(element => !element.endsWith('.js') && !element.endsWith('.ts'));
await Promise.all(
// For each categorie
modals_categories.map(async modals_category => {
// Retrieve all the commands
const modal_files = await readdir(`${__dirname}/${modals_category}`);
// Add the category to the collection for the help command
client.modals.categories.set(
modals_category,
modal_files.map(removeExtension),
);
// Add the modal
return Promise.all(
modal_files.map(async modal_file => {
const modal = (
await import(`../modals/${modals_category}/${modal_file}`)
).default;
// Add it to the collection so the interaction will work
client.modals.list.set(modal.data.name, modal);
return modal.data;
}),
);
}),
);
};

View file

@ -0,0 +1,21 @@
import { ModalSubmitInteraction } from 'discord.js';
import { getFilename } from '../../utils/misc';
export default {
data: {
name: getFilename(__filename),
},
interaction: async (interaction: ModalSubmitInteraction) => {
if (!interaction.isModalSubmit()) {
console.log('not modal called modal :/');
return;
}
const time = interaction.fields.fields.get('timeGUI')?.value;
return interaction.reply({
content: `${time}`,
ephemeral: true,
});
},
};

View file

@ -16,6 +16,28 @@ declare module 'discord.js' {
/** Default lang used */
default_lang: string
},
/** Store all the modals */
modals: {
categories: Collection<
/** Category name */
string,
/** Name of the modals in the category */
string[]
>,
list: Collection<
/** Modal name */
string,
/** Modal itself */
{
/** Data about the modal */
data: {
name: string
},
/** How the modal interact */
interaction: (interaction: ModalSubmitInteraction, client: Client) => unknown
}
>,
}
/** Store all the slash commands */
commands: {
categories: Collection<

View file

@ -19,6 +19,11 @@ export default async () => {
default_lang: process.env.DEFAULT_LANG ?? 'fr',
};
client.modals = {
categories: new Collection(),
list: new Collection(),
};
client.commands = {
categories: new Collection(),
list: new Collection(),

View file

@ -7,6 +7,7 @@ import { GuildMember } from 'discord.js';
* @returns String
*/
export const logStart = (name: string, status: boolean) => {
// TODO Handle precision about the error if status is false
return `> ${name} ${status === true ? '✅' : '❌'}`;
};