diff --git a/src/commands/Productivity/setsnooze.ts b/src/commands/Productivity/setsnooze.ts new file mode 100644 index 0000000..7662fc2 --- /dev/null +++ b/src/commands/Productivity/setsnooze.ts @@ -0,0 +1,21 @@ +import { SteveCommand } from '@lib/structures/commands/SteveCommand'; +import { GuildMessage } from '@lib/types/Messages'; +import { UserSettings } from '@lib/types/settings/UserSettings'; +import { ApplyOptions } from '@skyra/decorators'; +import { friendlyDuration } from '@utils/util'; +import { Message } from 'discord.js'; +import { CommandOptions } from 'klasa'; + +@ApplyOptions({ + description: lang => lang.tget('commandSetSnoozeDescription'), + usage: '' +}) +export default class extends SteveCommand { + + public async run(msg: GuildMessage, [duration]: [number]): Promise { + await msg.author.settings.update(UserSettings.SnoozeDuration, duration); + + return msg.channel.send(msg.guild.language.tget('commandSetSnoozeSet', friendlyDuration(duration))); + } + +} diff --git a/src/commands/Productivity/snooze.ts b/src/commands/Productivity/snooze.ts new file mode 100644 index 0000000..d4bc988 --- /dev/null +++ b/src/commands/Productivity/snooze.ts @@ -0,0 +1,36 @@ +import { CommandOptions, KlasaMessage } from 'klasa'; +import { Message } from 'discord.js'; +import { ApplyOptions, CreateResolver } from '@skyra/decorators'; +import { UserSettings } from '@lib/types/settings/UserSettings'; +import { SteveCommand } from '@lib/structures/commands/SteveCommand'; +import { friendlyDuration } from '@utils/util'; + +@ApplyOptions({ + description: lang => lang.tget('commandSnoozeDescription'), + extendedHelp: lang => lang.tget('commandSnoozeExtended'), + usage: '(duration:timespan)' +}) +@CreateResolver( + 'timespan', + (str, possible, msg) => str + ? msg.client.arguments.get('timespan').run(str, possible, msg) + : msg.author.settings.get(UserSettings.SnoozeDuration) +) +export default class extends SteveCommand { + + public async run(msg: KlasaMessage, [duration]: [number]): Promise { + const reminder = this.client.schedule.getUserSnooze(msg.author.id); + if (!reminder) return msg.channel.send(msg.language.tget('commandSnoozeNoRemind')); + + await this.client.schedule.createReminder(duration, + // @ts-expect-error 2339 + reminder.data.userID ?? reminder.data.user, reminder.data.content, + // @ts-expect-error 2339 + reminder.data.channelID ?? reminder.data.channel); + + await reminder.delete(); + + return msg.channel.send(msg.language.tget('commandSnoozeCreated', reminder.data.content, friendlyDuration(duration))); + } + +} diff --git a/src/extendables/Schedule.ts b/src/extendables/Schedule.ts index d66da6f..95b1867 100644 --- a/src/extendables/Schedule.ts +++ b/src/extendables/Schedule.ts @@ -1,3 +1,4 @@ +import { Time } from '@lib/types/Enums'; import { ApplyOptions } from '@skyra/decorators'; import { Extendable, ExtendableOptions, Schedule, ScheduledTask } from 'klasa'; @@ -21,6 +22,13 @@ export default class extends Extendable { }); } + public createSnooze(this: Schedule, userID: string, content: string, channelID: string): Promise { + return this.create('snooze', Date.now() + (5 * Time.MINUTE), { + catchUp: true, + data: { userID, content, channelID } + }); + } + public getUserReminders(this: Schedule, userID: string): Reminder[] { const filter = (task: ScheduledTask) => { const id = task.data.userID ?? task.data.user; @@ -29,6 +37,13 @@ export default class extends Extendable { return this.tasks.filter(filter); } + public getUserSnooze(this: Schedule, userID: string): Reminder | undefined { + return this.tasks.filter((task: ScheduledTask) => { + const id = task.data.userID ?? task.data.user; + return task.taskName === 'snooze' && id === userID; + }).pop(); + } + } export type ModerationTask = 'unmute' | 'undeafen' | 'unban'; diff --git a/src/languages/en-US.ts b/src/languages/en-US.ts index 2de1e2a..164f20b 100644 --- a/src/languages/en-US.ts +++ b/src/languages/en-US.ts @@ -805,6 +805,19 @@ export default class extends Language { commandRemindViewEmbed: { title: 'Pending Reminders' }, + commandSnoozeDescription: 'Repeat your last reminder.', + commandSnoozeExtended: builder.display('snooze', { + examples: [ + '', + '5m' + ], + reminder: 'You can only snooze reminders that happened in the past 5 minutes.', + extendedHelp: 'You can change your default snooze time with the `setsnooze` command.' + }), + commandSnoozeCreated: (content, duration) => `I'll remind you **${content}** in ${duration}.`, + commandSnoozeNoRemind: 'It looks like you haven\'t had any reminders go off in the past 5 minutes.', + commandSetSnoozeDescription: 'Set your default snooze duration.', + commandSetSnoozeSet: duration => `Your default snooze duration is now ${duration}.`, /** * ################################ * # POMODORO # diff --git a/src/lib/schemas/User.ts b/src/lib/schemas/User.ts index e8f5da3..39b04d1 100644 --- a/src/lib/schemas/User.ts +++ b/src/lib/schemas/User.ts @@ -1,4 +1,6 @@ +import { Time } from '@lib/types/Enums'; import { Client } from 'klasa'; export default Client.defaultUserSchema - .add('embedColor', 'Color'); + .add('embedColor', 'Color') + .add('snoozeDuration', 'Integer', { 'default': 30 * Time.MINUTE }); diff --git a/src/lib/types/Augments.d.ts b/src/lib/types/Augments.d.ts index b77f51f..3bec0bc 100644 --- a/src/lib/types/Augments.d.ts +++ b/src/lib/types/Augments.d.ts @@ -48,7 +48,9 @@ declare module 'klasa' { interface Schedule { createModerationTask(taskName: ModerationTask, duration: number, taskData: ModerationTaskData): Promise; createReminder(duration: number, userID: string, content: string, channelID: string): Promise; + createSnooze(userID: string, content: string, channelID: string): Promise; getUserReminders(userID: string): Reminder[]; + getUserSnooze(userID: string): Reminder; } } diff --git a/src/lib/types/Languages.d.ts b/src/lib/types/Languages.d.ts index b7754fc..70a0c04 100644 --- a/src/lib/types/Languages.d.ts +++ b/src/lib/types/Languages.d.ts @@ -319,6 +319,12 @@ declare module 'klasa' { commandRemindViewEmbed: { title: string; }; + commandSnoozeDescription: string; + commandSnoozeExtended: string; + commandSnoozeNoRemind: string; + commandSnoozeCreated: (content: string, duration: string) => string; + commandSetSnoozeDescription: string; + commandSetSnoozeSet: (duration: string) => string; commandPomodoroDescription: string; commandPomodoroExtended: string; commandPomodoroUnderConstruction: string; diff --git a/src/lib/types/settings/UserSettings.ts b/src/lib/types/settings/UserSettings.ts index 7d02bbf..e1706aa 100644 --- a/src/lib/types/settings/UserSettings.ts +++ b/src/lib/types/settings/UserSettings.ts @@ -2,5 +2,6 @@ export namespace UserSettings { export const EmbedColor = 'embedColor'; + export const SnoozeDuration = 'snoozeDuration'; } diff --git a/src/tasks/reminder.ts b/src/tasks/reminder.ts index 95448f7..b394083 100644 --- a/src/tasks/reminder.ts +++ b/src/tasks/reminder.ts @@ -2,6 +2,7 @@ import { Task } from 'klasa'; import { Message } from 'discord.js'; import { OldReminderData, ReminderData } from '../extendables/Schedule'; +import { floatPromise } from '@utils/util'; export default class extends Task { @@ -11,7 +12,11 @@ export default class extends Task { // @ts-expect-error 2339 const _user = await this.client.users.fetch(data.userID ?? data.user); - if (_channel && _channel.isText()) return _channel.send(`${_user}, here's the reminder you asked for: **${data.content}**`); + if (_channel && _channel.isText()) { + // @ts-expect-error 2339 + floatPromise(this, this.client.schedule.createSnooze(data.userID ?? data.user, data.content, data.channelID ?? data.channel)); + return _channel.send(`${_user}, here's the reminder you asked for: **${data.content}**`); + } } } diff --git a/src/tasks/snooze.ts b/src/tasks/snooze.ts new file mode 100644 index 0000000..33c627a --- /dev/null +++ b/src/tasks/snooze.ts @@ -0,0 +1,11 @@ + +import { Task } from 'klasa'; +import { OldReminderData, ReminderData } from '../extendables/Schedule'; + +export default class extends Task { + + public run(data: ReminderData | OldReminderData): ReminderData | OldReminderData { + return data; + } + +}