feat: Reminders #44
5 changed files with 92 additions and 70 deletions
|
@ -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,
|
|
||||||
}
|
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!",
|
||||||
|
|
|
@ -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
52
src/utils/reminder.ts
Normal 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}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
Loading…
Reference in a new issue