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 { Client, ChatInputCommandInteraction, ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } from 'discord.js';
import { getLocalizations } from '../../utils/locales';
import { ActionRowBuilder, ChatInputCommandInteraction, Client, ModalBuilder, TextInputBuilder, TextInputStyle } from 'discord.js';
import { getLocale, getLocalizations } from '../../utils/locales';
import { getFilename } from '../../utils/misc';
import { strToSeconds } from '../../utils/time';
import { newReminder } from '../../utils/reminder';
export default {
data: (client: Client) => {
@ -140,6 +140,7 @@ export default {
interaction: async (interaction: ChatInputCommandInteraction, client: Client) => {
const loc_default = client.locales.get(client.config.default_lang);
const filename = getFilename(__filename);
const loc = getLocale(client, interaction.locale);
/* Votre code ici */
const subcommand = interaction.options.getSubcommand();
@ -147,67 +148,43 @@ export default {
// New reminder
case loc_default?.get(`c_${filename}_sub1_name`)
?.toLowerCase() ?? '': {
// TODO: Ici il y a 2 options, l'un pour le temps et l'autre
// 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;
const time = interaction.options.getString(loc_default?.get(`c_${filename}_sub1_opt1_name`) as string);
if (time != null) {
// Cli
// Split time
if (time?.endsWith('@')) {
time = time.slice(0, -1);
option = OptionReminder.Mention;
} else if (time?.toLowerCase().endsWith('p')) {
time = time.slice(0, -1);
option = OptionReminder.DirectMessage;
}
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}`);
return newReminder(client, time, {
message: interaction.options.getString(loc_default?.get('c_reminder_sub1_opt2_name') as string),
createdAt: interaction.createdAt.getTime(),
channelId: interaction.channelId,
userId: interaction.user.id,
guildId: interaction.guildId,
}).then((msg) => interaction.reply({
content: msg as string,
ephemeral: true,
}));
} else {
// GUI
// TODO: local
const modal = new ModalBuilder()
.setCustomId('reminderGUI')
.setTitle('LOC_reminder');
.setTitle(loc?.get('c_reminder_name').capitalize());
// TODO: local
const timeGUI = new TextInputBuilder()
.setCustomId('timeGUI')
.setLabel('LOC_time')
.setCustomId('reminderGUI-time')
.setLabel(loc?.get('c_reminder_sub1_opt1_name').capitalize())
.setStyle(TextInputStyle.Short)
.setPlaceholder('1h')
.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
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);
if (!modal) {
return interaction.reply({
// TODO: locale
content: `can't find ${interaction.customId}`,
content: loc.get('e_interacreate_no_modal'),
ephemeral: true,
});
}

View file

@ -1,5 +1,6 @@
{
"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_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 { newReminder } from '../../utils/reminder';
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}`,
interaction: async (interaction: ModalSubmitInteraction, client: Client) => {
return newReminder(client, interaction.fields.fields.get('reminderGUI-time')?.value as string, {
message: interaction.fields.fields.get('reminderGUI-message')?.value ?? null,
createdAt: interaction.createdAt.getTime(),
channelId: interaction.channelId,
userId: interaction.user.id,
guildId: interaction.guildId,
}).then((msg) => interaction.reply({
content: msg as string,
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}`);
});
});
};