feat: Reminders #44

Merged
Anri merged 54 commits from feat/reminders into main 2023-01-17 12:15:15 +01:00
5 changed files with 92 additions and 70 deletions
Showing only changes of commit c7933d4aa9 - Show all commits

View file

@ -1,8 +1,8 @@
import { ModalActionRowComponentBuilder, SlashCommandBuilder } from '@discordjs/builders'; import { ModalActionRowComponentBuilder, SlashCommandBuilder } from '@discordjs/builders';
import { Client, ChatInputCommandInteraction, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } from 'discord.js'; import { ActionRowBuilder, ChatInputCommandInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle } from 'discord.js';
import { getLocalizations } from '../../utils/locales'; import { getLocale, getLocalizations } from '../../utils/locales';
import { getFilename } from '../../utils/misc'; import { getFilename } from '../../utils/misc';
import { strToSeconds } from '../../utils/time'; import { newReminder } from '../../utils/reminder';
export default { export default {
data: (client: Client) => { data: (client: Client) => {
@ -140,6 +140,7 @@ export default {
interaction: async (interaction: ChatInputCommandInteraction, client: Client) => { interaction: async (interaction: ChatInputCommandInteraction, client: Client) => {
const loc_default = client.locales.get(client.config.default_lang); const loc_default = client.locales.get(client.config.default_lang);
const filename = getFilename(__filename); const filename = getFilename(__filename);
const loc = getLocale(client, interaction.locale);
/* Votre code ici */ /* Votre code ici */
const subcommand = interaction.options.getSubcommand(); const subcommand = interaction.options.getSubcommand();
@ -147,67 +148,43 @@ export default {
// New reminder // New reminder
case loc_default?.get(`c_${filename}_sub1_name`) case loc_default?.get(`c_${filename}_sub1_name`)
?.toLowerCase() ?? '': { ?.toLowerCase() ?? '': {
// TODO: Ici il y a 2 options, l'un pour le temps et l'autre const time = interaction.options.getString(loc_default?.get(`c_${filename}_sub1_opt1_name`) as string);
// pour le message, il faut tout le temps un temps, mais pas
// tout le temps de message (= message par défaut, le reminder
// fait office de compte à rebours tout simple dans ce cas là)
// Alors j'avais comme idée de pas mettre le temps comme requis,
// et quand pas de temps est spécifié dans la commande, on ouvre
// une boîte de dialogue : https://discordjs.guide/interactions/modals.html#building-and-responding-with-modals
// et on demande à l'utilisateur de remplir les champs comme ça.
// Avec cette technique on a les commandes pour les "poweruser"
// qui préfèrent tout faire en ligne de commandes et un truc
// plus user-friendly avec une interface (et en plus c'est
// nouveau et cool)
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;
let seconds: number;
if (time != null) { if (time != null) {
// Cli // Cli
return newReminder(client, time, {
// Split time message: interaction.options.getString(loc_default?.get('c_reminder_sub1_opt2_name') as string),
if (time?.endsWith('@')) { createdAt: interaction.createdAt.getTime(),
time = time.slice(0, -1); channelId: interaction.channelId,
option = OptionReminder.Mention; userId: interaction.user.id,
} else if (time?.toLowerCase().endsWith('p')) { guildId: interaction.guildId,
time = time.slice(0, -1); }).then((msg) => interaction.reply({
option = OptionReminder.DirectMessage; content: msg as string,
} ephemeral: true,
}));
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 { } else {
// GUI // GUI
// TODO: local
const modal = new ModalBuilder() const modal = new ModalBuilder()
.setCustomId('reminderGUI') .setCustomId('reminderGUI')
.setTitle('LOC_reminder'); .setTitle(loc?.get('c_reminder_name').capitalize());
// TODO: local
const timeGUI = new TextInputBuilder() const timeGUI = new TextInputBuilder()
.setCustomId('timeGUI') .setCustomId('reminderGUI-time')
.setLabel('LOC_time') .setLabel(loc?.get('c_reminder_sub1_opt1_name').capitalize())
.setStyle(TextInputStyle.Short) .setStyle(TextInputStyle.Short)
.setPlaceholder('1h') .setPlaceholder('1h')
.setRequired(true); .setRequired(true);
modal.addComponents(new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(timeGUI)); const messageGUI = new TextInputBuilder()
.setCustomId('reminderGUI-message')
.setLabel(loc?.get('c_reminder_sub1_opt2_name').capitalize())
.setStyle(TextInputStyle.Paragraph)
.setPlaceholder(loc?.get('c_reminder_sub1_opt2_desc'))
.setRequired(false);
await interaction.showModal(modal); modal.addComponents(new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(timeGUI), new ActionRowBuilder<ModalActionRowComponentBuilder>().addComponents(messageGUI));
// Response of the modal in /src/modals/misc/reminder return interaction.showModal(modal);
} }
break;
} }
// List reminders // List reminders
case loc_default?.get(`c_${filename}_sub2_name`) case loc_default?.get(`c_${filename}_sub2_name`)
@ -236,10 +213,3 @@ export default {
} }
}, },
}; };
enum OptionReminder {
Nothing,
Mention,
DirectMessage,
}

View file

@ -21,8 +21,7 @@ export default (interaction: Interaction, client: Client) => {
const modal = client.modals.list.get(interaction.customId); const modal = client.modals.list.get(interaction.customId);
if (!modal) { if (!modal) {
return interaction.reply({ return interaction.reply({
// TODO: locale content: loc.get('e_interacreate_no_modal'),
content: `can't find ${interaction.customId}`,
ephemeral: true, ephemeral: true,
}); });
} }

View file

@ -1,5 +1,6 @@
{ {
"e_interacreate_no_command": "Désolé, la commande n'existe plus...", "e_interacreate_no_command": "Désolé, la commande n'existe plus...",
"e_interacreate_no_modal": "Désolé, le modèle n'existe plus...",
"c_ping_name": "Ping", "c_ping_name": "Ping",
"c_ping_desc": "Pong!", "c_ping_desc": "Pong!",

View file

@ -1,21 +1,21 @@
import { ModalSubmitInteraction } from 'discord.js'; import { Client, ModalSubmitInteraction } from 'discord.js';
import { getFilename } from '../../utils/misc'; import { getFilename } from '../../utils/misc';
import { newReminder } from '../../utils/reminder';
export default { export default {
data: { data: {
name: getFilename(__filename), name: getFilename(__filename),
}, },
interaction: async (interaction: ModalSubmitInteraction) => { interaction: async (interaction: ModalSubmitInteraction, client: Client) => {
if (!interaction.isModalSubmit()) { return newReminder(client, interaction.fields.fields.get('reminderGUI-time')?.value as string, {
console.log('not modal called modal :/'); message: interaction.fields.fields.get('reminderGUI-message')?.value ?? null,
return; createdAt: interaction.createdAt.getTime(),
} channelId: interaction.channelId,
userId: interaction.user.id,
const time = interaction.fields.fields.get('timeGUI')?.value; guildId: interaction.guildId,
}).then((msg) => interaction.reply({
return interaction.reply({ content: msg as string,
content: `${time}`,
ephemeral: true, ephemeral: true,
}); }));
}, },
}; };

52
src/utils/reminder.ts Normal file
View file

@ -0,0 +1,52 @@
import { Client } from 'discord.js';
import { strToSeconds } from './time';
export enum OptionReminder {
Nothing,
Mention,
DirectMessage,
}
export type infoReminder = {
message: string | null,
createdAt: number,
channelId: string | null,
userId: string,
guildId: string | null
}
const splitTime = (time: string) => {
if (time?.endsWith('@')) {
return { time: time.slice(0, -1), option: OptionReminder.Mention };
} else if (time?.toLowerCase().endsWith('p')) {
return { time: time.slice(0, -1), option: OptionReminder.DirectMessage };
}
return { time: time, option: OptionReminder.Nothing };
};
export const newReminder = async (client: Client, time: string, info: infoReminder) => {
const data = splitTime(time);
// Add the remind to the db
return new Promise((ok, ko) => {
const res = client.db.run('INSERT INTO reminder ( \
data, expiration_date, option_id, channel_id, creation_date, user_id, guild_id \
) VALUES ( ?, ?, ?, ?, ?, ?, ?);', [
info.message,
info.createdAt + strToSeconds(data.time),
data.option.valueOf(),
info.channelId,
info.createdAt,
info.userId,
info.guildId], (err) => {
if (err) {
ko(err);
}
// Send confirmation to user
// TODO: local
ok(`ratio: ${info.message}, ${data.time}=${strToSeconds(data.time)}, ${data.option}, ${res}`);
});
});
};