timeout.ts

1import {
2	ChatInputCommandInteraction,
3	PermissionFlagsBits,
4	SlashCommandBuilder,
5} from 'discord.js'
6import { Command } from '@/types/bot'
7
8export default {
9	data: new SlashCommandBuilder()
10		.setName('timeout')
11		.setDescription('Timeout a user')
12		.addUserOption((option) =>
13			option
14				.setName('user')
15				.setDescription('The user to timeout')
16				.setRequired(true),
17		)
18		.addStringOption((option) =>
19			option
20				.setName('duration')
21				.setDescription('Timeout duration (e.g., 1h, 30m, 1d)')
22				.setRequired(true),
23		)
24		.addStringOption((option) =>
25			option
26				.setName('reason')
27				.setDescription('Reason for the timeout')
28				.setRequired(false),
29		)
30		.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers),
31
32	async execute(interaction: ChatInputCommandInteraction) {
33		const target = interaction.options.getUser('user', true)
34		const durationStr = interaction.options.getString('duration', true)
35		const reason =
36			interaction.options.getString('reason') ?? 'No reason provided'
37
38		const durationMatch = durationStr.match(/^(\d+)([hmd])$/)
39		if (!durationMatch) {
40			await interaction.reply({
41				content: 'Invalid duration format! Use format like: 1h, 30m, or 1d',
42				ephemeral: true,
43			})
44			return
45		}
46
47		const [, amount, unit] = durationMatch
48		const multiplier =
49			unit === 'h' ? 3600000
50			: unit === 'm' ? 60000
51			: 86400000
52		const duration = parseInt(amount) * multiplier
53
54		if (duration > 2419200000) {
55			// 28 days in milliseconds
56			await interaction.reply({
57				content: 'Timeout duration cannot be longer than 28 days!',
58				ephemeral: true,
59			})
60			return
61		}
62
63		const member = interaction.guild?.members.cache.get(target.id)
64
65		if (!member) {
66			await interaction.reply({
67				content: 'User not found in this server!',
68				ephemeral: true,
69			})
70			return
71		}
72
73		if (!member.moderatable) {
74			await interaction.reply({
75				content: 'I cannot timeout this user!',
76				ephemeral: true,
77			})
78			return
79		}
80
81		await member.timeout(
82			duration,
83			`${reason} - Muted by ${interaction.user.tag}`,
84		)
85		await interaction.reply(`🔇 **Timed out ${target.tag}**\nReason: ${reason}`)
86	},
87} as Command
88