aboutsummaryrefslogtreecommitdiff
path: root/src/commands/config/features.ts
blob: 5eafb0c44ebaaabae3d9995be313ef978cb33081 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import {
	BushCommand,
	clientSendAndPermCheck,
	colors,
	emojis,
	guildFeaturesArr,
	guildFeaturesObj,
	type CommandMessage,
	type GuildFeatures,
	type SlashMessage
} from '#lib';
import assert from 'assert';
import {
	ActionRowBuilder,
	ComponentType,
	EmbedBuilder,
	PermissionFlagsBits,
	SelectMenuBuilder,
	type Message,
	type SelectMenuInteraction
} from 'discord.js';

export default class FeaturesCommand extends BushCommand {
	public constructor() {
		super('features', {
			aliases: ['features'],
			category: 'config',
			description: 'Toggle the features of the server.',
			usage: ['features'],
			examples: ['features'],
			slash: true,
			channel: 'guild',
			clientPermissions: (m) => clientSendAndPermCheck(m, [PermissionFlagsBits.EmbedLinks], true),
			userPermissions: [PermissionFlagsBits.ManageGuild]
		});
	}

	public override async exec(message: CommandMessage | SlashMessage) {
		assert(message.inGuild());

		const featureEmbed = new EmbedBuilder().setTitle(`${message.guild.name}'s Features`).setColor(colors.default);

		const enabledFeatures = await message.guild.getSetting('enabledFeatures');
		this.generateDescription(guildFeaturesArr, enabledFeatures, featureEmbed);
		const components = this.generateComponents(guildFeaturesArr, false);
		const msg = (await message.util.reply({ embeds: [featureEmbed], components: [components] })) as Message;
		const collector = msg.createMessageComponentCollector({
			componentType: ComponentType.SelectMenu,
			time: 300_000,
			filter: (i) => i.guildId === msg.guildId && i.message?.id === msg.id
		});

		collector.on('collect', async (interaction: SelectMenuInteraction) => {
			if (interaction.user.id === message.author.id || this.client.config.owners.includes(interaction.user.id)) {
				assert(message.inGuild());

				const [selected]: GuildFeatures[] = interaction.values as GuildFeatures[];

				if (!guildFeaturesArr.includes(selected)) throw new Error('Invalid guild feature selected');

				const newEnabledFeatures = await message.guild.toggleFeature(selected, message.member!);

				this.generateDescription(guildFeaturesArr, newEnabledFeatures, featureEmbed);

				await interaction.update({ embeds: [featureEmbed] }).catch(() => undefined);
				return;
			} else {
				await interaction?.deferUpdate().catch(() => undefined);
				return;
			}
		});

		collector.on('end', async () => {
			await msg.edit({ components: [this.generateComponents(guildFeaturesArr, false)] }).catch(() => undefined);
		});
	}

	public generateDescription(allFeatures: GuildFeatures[], currentFeatures: GuildFeatures[], embed: EmbedBuilder): void {
		embed.setDescription(
			allFeatures
				.map(
					(feature) => `${currentFeatures.includes(feature) ? emojis.check : emojis.cross} **${guildFeaturesObj[feature].name}**`
				)
				.join('\n')
		);
	}

	public generateComponents(guildFeatures: GuildFeatures[], disable: boolean) {
		return new ActionRowBuilder<SelectMenuBuilder>().addComponents(
			new SelectMenuBuilder({
				customId: 'command_selectFeature',
				disabled: disable,
				maxValues: 1,
				minValues: 1,
				options: guildFeatures
					.filter((f) => !guildFeaturesObj[f].hidden)
					.map((f) => ({
						label: guildFeaturesObj[f].name,
						value: f,
						description: guildFeaturesObj[f].description
					}))
			})
		);
	}
}