Polarcraft/discordbot/commands/team.js

209 lines
8.3 KiB
JavaScript

const { SlashCommandBuilder, ModalBuilder, TextInputStyle, TextInputBuilder, ActionRowBuilder, ChannelType, PermissionsBitField, ButtonBuilder, ButtonStyle, ComponentType } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Users, Team } = require('../functions/models.js');
const { applyUsername } = require('../functions/utils.js');
const { client } = require('../index.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('team')
.setDescription('Team command')
.addSubcommand(subcommand => subcommand
.setName('create')
.setDescription('Create a team'))
.addSubcommand(subcommand => subcommand
.setName('invite')
.setDescription('Invite an user')
.addUserOption(option => option
.setName('user')
.setDescription('The user to invite')
.setRequired(true)))
.addSubcommand(subcommand => subcommand
.setName('leave')
.setDescription('Leave your team')),
async execute(interaction) {
const user = await Users.findOne({ where: { id: interaction.user.id } });
if (!user) return await interaction.reply({ embeds: [simpleEmbed('Error while getting user information')], ephemeral: true });
if (interaction.options.getSubcommand() === 'create') {
if (user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are already in a team')], ephemeral: true });
const modal = new ModalBuilder()
.setCustomId('teamCreate')
.setTitle('Create team');
const nameInput = new TextInputBuilder()
.setCustomId('nameInput')
.setLabel('Team name')
.setMinLength(3)
.setMaxLength(16)
.setStyle(TextInputStyle.Short);
const colorInput = new TextInputBuilder()
.setCustomId('colorInput')
.setLabel('Team color (hex)')
.setStyle(TextInputStyle.Short)
.setPlaceholder('#00ff00');
const firstActionRow = new ActionRowBuilder().addComponents(nameInput);
const secondActionRow = new ActionRowBuilder().addComponents(colorInput);
modal.addComponents(firstActionRow, secondActionRow);
await interaction.showModal(modal);
try {
const filter = (filterInteraction) => filterInteraction.customId === 'teamCreate';
const modalInteraction = await interaction.awaitModalSubmit({ filter, time: 10 * 60 * 1000 });
const teamName = modalInteraction.fields.getTextInputValue('nameInput');
const teamColor = modalInteraction.fields.getTextInputValue('colorInput');
if (!/^[a-zA-Z0-9]+$/.test(teamName)) return await modalInteraction.reply({ embeds: [simpleEmbed('Team name can only include alphanumeric characters')], ephemeral: true });
if (!/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(teamColor)) return await modalInteraction.reply({ embeds: [simpleEmbed('Team color must be a valid hex code. [Color Picker](https://htmlcolorcodes.com/color-picker/)')], ephemeral: true });
const guild = await client.guilds.fetch(process.env.GUILD_ID);
const category = await guild.channels.fetch(process.env.TEAM_CATEGORY_ID);
const textChannel = await guild.channels.create({
name: teamName,
type: ChannelType.GuildText,
parent: category,
permissionOverwrites: [
{
id: guild.id,
deny: [PermissionsBitField.Flags.ViewChannel],
},
{
id: interaction.member.id,
allow: [PermissionsBitField.Flags.ViewChannel],
},
],
});
const voiceChannel = await guild.channels.create({
name: teamName,
type: ChannelType.GuildVoice,
parent: category,
permissionOverwrites: [
{
id: guild.id,
deny: [PermissionsBitField.Flags.ViewChannel],
},
{
id: interaction.member.id,
allow: [PermissionsBitField.Flags.ViewChannel],
},
],
});
const team = await Team.create({
name: teamName,
color: teamColor,
textChannelId: textChannel.id,
voiceChannelId: voiceChannel.id,
});
await team.addMembers([ user ]);
await applyUsername(user, interaction.member);
await modalInteraction.reply({ embeds: [simpleEmbed(`Successfully created team **${teamName}**`)], ephemeral: true });
} catch (error) {
console.error(error);
}
} else if (interaction.options.getSubcommand() === 'leave') {
if (!user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are not in a team')], ephemeral: true });
const team = await user.getTeam();
await team.removeMember(user);
const guild = await client.guilds.fetch(process.env.GUILD_ID);
const textChannel = await guild.channels.fetch(team.textChannelId);
const voiceChannel = await guild.channels.fetch(team.voiceChannelId);
if (await team.countMembers() <= 0) {
await textChannel.delete();
await voiceChannel.delete();
await team.destroy();
} else {
await textChannel.permissionOverwrites.delete(interaction.member);
await voiceChannel.permissionOverwrites.delete(interaction.member);
}
await applyUsername(user, interaction.member);
await interaction.reply({ embeds: [simpleEmbed('Successfully left team')], ephemeral: true });
} else if (interaction.options.getSubcommand() === 'invite') {
if (!user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are not in a team')], ephemeral: true });
const invitedUser = interaction.options.getUser('user');
if (interaction.user.id === invitedUser.id) return await interaction.reply({ embeds: [simpleEmbed('You cannot invite yourself')], ephemeral: true });
const invitedUserInstance = await Users.findOne({ where: { id: invitedUser.id } });
if (invitedUserInstance.teamId) return await interaction.reply({ embeds: [simpleEmbed('The user you are trying already is in a team')], ephemeral: true });
const team = await user.getTeam();
const acceptButton = new ButtonBuilder()
.setCustomId('accept')
.setLabel('Accept')
.setStyle(ButtonStyle.Success);
const denyButton = new ButtonBuilder()
.setCustomId('deny')
.setLabel('Deny')
.setStyle(ButtonStyle.Danger);
const row = new ActionRowBuilder()
.addComponents(acceptButton, denyButton);
const inviteMessage = await invitedUser.send({
embeds: [simpleEmbed(`**${user.rawUsername}** invited you to join team **${team.name}**`)],
components: [row],
});
await interaction.reply({ embeds: [simpleEmbed(`Successfully invited ${invitedUser} to your team`)], ephemeral: true });
const collector = inviteMessage.createMessageComponentCollector({ componentType: ComponentType.Button, time: 60 * 60 * 1000 });
collector.on('collect', async i => {
try {
if (i.customId === 'accept') {
await invitedUserInstance.reload();
if (invitedUserInstance.teamId) return await i.message.edit({ embeds: [simpleEmbed('You are already in a team')], components: [] });
await team.addMember(i.user.id);
const guild = await client.guilds.fetch(process.env.GUILD_ID);
const member = await guild.members.fetch(i.user.id);
const textChannel = await guild.channels.fetch(team.textChannelId);
const voiceChannel = await guild.channels.fetch(team.voiceChannelId);
await textChannel.permissionOverwrites.edit(member, { ViewChannel: true });
await voiceChannel.permissionOverwrites.edit(member, { ViewChannel: true });
await applyUsername(invitedUserInstance, member);
await i.message.edit({ embeds: [simpleEmbed(`Successfully joined team **${team.name}**`)], components: [] });
} else if (i.customId === 'deny') {
await i.message.edit({ embeds: [simpleEmbed(`Successfully denied the request to join team **${team.name}**`)], components: [] });
}
} catch (error) {
console.error(error);
}
});
collector.on('end', async () => {
inviteMessage.edit({ embeds: [simpleEmbed('Confirmation not received within 1 hour, cancelling')], components: [] });
});
}
},
};