From 934e6493c9c5955cbe5c1990a3d2239fd0a90539 Mon Sep 17 00:00:00 2001 From: Oleksandr Honcharov <0976053529@ukr.net> Date: Thu, 6 Jun 2024 04:07:44 +0300 Subject: [PATCH] welcome role / feedback command --- src/commands/feedback.ts | 52 +++++++++++++++++ src/commands/set-welcome-channel.ts | 9 +++ src/db.ts | 1 + src/events/guildMemberAdd.ts | 15 +++-- src/main.ts | 91 +++++++++++------------------ 5 files changed, 105 insertions(+), 63 deletions(-) create mode 100644 src/commands/feedback.ts diff --git a/src/commands/feedback.ts b/src/commands/feedback.ts new file mode 100644 index 0000000..fe015ed --- /dev/null +++ b/src/commands/feedback.ts @@ -0,0 +1,52 @@ +import { Discord, Slash, SlashChoice, SlashOption } from 'discordx' +import { + ApplicationCommandOptionType, + CommandInteraction, + EmbedBuilder, +} from 'discord.js' +import { db, DBTableEnum } from '../db.ts' + +@Discord() +export class Feedback { + @Slash({ + name: 'feedback', + description: 'Leave a feedback', + }) + async feedback( + @SlashChoice('⭐', '⭐⭐', '⭐⭐⭐', '⭐⭐⭐⭐', '⭐⭐⭐⭐⭐') + @SlashOption({ + name: 'rating', + description: 'Leave you review', + required: true, + type: ApplicationCommandOptionType.String, + }) + rating: string, + @SlashOption({ + name: 'description', + description: 'Leave a description about job', + required: true, + type: ApplicationCommandOptionType.String, + }) + description: string, + interaction: CommandInteraction, + ) { + const reviewChannelID = await db.get(DBTableEnum.FEEDBACK_CHANNEL) + + const embed = new EmbedBuilder() + .setTitle(`⭐ Review by ${interaction.user.username}`) + .setDescription(`Author: <@${interaction.user.id}>`) + .setThumbnail(interaction.user.avatarURL()) + .setFields([ + { name: 'Evaluation of support work:', value: rating }, + { name: 'Commentary:', value: '```' + description + '```' }, + ]) + + const channel = await interaction.guild?.channels.fetch(reviewChannelID) + + if (channel?.isTextBased()) { + channel.send({ embeds: [embed] }) + } + + await interaction.reply({ ephemeral: true, content: 'Review sent!' }) + } +} diff --git a/src/commands/set-welcome-channel.ts b/src/commands/set-welcome-channel.ts index 1dde907..e2f6ea6 100644 --- a/src/commands/set-welcome-channel.ts +++ b/src/commands/set-welcome-channel.ts @@ -2,6 +2,7 @@ import { Discord, Slash, SlashOption } from 'discordx' import { ApplicationCommandOptionType, CommandInteraction, + Role, TextChannel, } from 'discord.js' import { db, DBTableEnum } from '../db.ts' @@ -17,9 +18,17 @@ export class SetWelcomeChannel { required: true, }) channel: TextChannel, + @SlashOption({ + name: 'role', + description: 'Role which will be given to user', + type: ApplicationCommandOptionType.Role, + required: true, + }) + role: Role, interaction: CommandInteraction, ) { await db.set(DBTableEnum.WELCOME_CHANNEL, channel.id) + await db.set(DBTableEnum.WELCOME_ROLE, role.id) await interaction.reply({ ephemeral: true, content: 'Success.' }) } } diff --git a/src/db.ts b/src/db.ts index 28d9087..3ec6ca6 100644 --- a/src/db.ts +++ b/src/db.ts @@ -3,6 +3,7 @@ export const db = new QuickDB() export enum DBTableEnum { WELCOME_CHANNEL = 'WELCOME_CHANNEL', + WELCOME_ROLE = 'WELCOME_ROLE', TICKET_CHANNEL = 'TICKET_CHANNEL', FEEDBACK_CHANNEL = 'FEEDBACK_CHANNEL', PORTFOLIO_CHANNEL = 'PORTFOLIO_CHANNEL', diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts index ee06727..6f358b8 100644 --- a/src/events/guildMemberAdd.ts +++ b/src/events/guildMemberAdd.ts @@ -1,5 +1,5 @@ import { ArgsOf, Discord, On } from 'discordx' -import { EmbedBuilder } from 'discord.js' +import { EmbedBuilder, channelMention, userMention } from 'discord.js' import { db, DBTableEnum } from '../db.ts' @Discord() @@ -13,23 +13,28 @@ export class GuildMemberAdd { const welcomeChannelID = await db.get(DBTableEnum.WELCOME_CHANNEL) const imageURL = await db.get(DBTableEnum.BANNER_URL) + const roleID = await db.get(DBTableEnum.WELCOME_ROLE) + let embed = new EmbedBuilder() .setTitle( `I'm glad to see you on my server. Let me give you a little tour.`, ) .setDescription( - `> 1. In the https://discord.com/channels/1248048650886578247/${portfolioChannelID} - you can see my previous works. - > 2. Here https://discord.com/channels/1248048650886578247/${makeAnOrderChannelID} you might open a ticket.`, + `> 1. In the ${channelMention(portfolioChannelID)} - you can see my previous works. + > 2. Here ${channelMention(makeAnOrderChannelID)} you might open a ticket.`, ) .setImage(imageURL) const channel = await member.guild.channels.fetch(welcomeChannelID) + const role = await member.guild.roles.fetch(roleID) - if (channel?.isTextBased()) { + if (channel?.isTextBased() && role) { channel.send({ embeds: [embed], - content: `What's up, <@${member.id}>`, + content: `What's up, ${userMention(member.id)}`, }) + + await member.roles.add(role) } } } diff --git a/src/main.ts b/src/main.ts index 11cb044..c957f0e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,73 +1,48 @@ -import { dirname, importx } from "@discordx/importer"; -import type { Interaction, Message } from "discord.js"; -import { IntentsBitField } from "discord.js"; -import { Client } from "discordx"; +import { dirname, importx } from '@discordx/importer' +import type { Interaction, Message } from 'discord.js' +import { IntentsBitField } from 'discord.js' +import { Client } from 'discordx' import 'dotenv/config' export const bot = new Client({ - // To use only guild command - // botGuilds: [(client) => client.guilds.cache.map((guild) => guild.id)], + intents: [ + IntentsBitField.Flags.Guilds, + IntentsBitField.Flags.GuildMembers, + IntentsBitField.Flags.GuildMessages, + IntentsBitField.Flags.GuildMessageReactions, + IntentsBitField.Flags.GuildVoiceStates, + IntentsBitField.Flags.MessageContent, + ], - // Discord intents - intents: [ - IntentsBitField.Flags.Guilds, - IntentsBitField.Flags.GuildMembers, - IntentsBitField.Flags.GuildMessages, - IntentsBitField.Flags.GuildMessageReactions, - IntentsBitField.Flags.GuildVoiceStates, - IntentsBitField.Flags.MessageContent, - ], + silent: false, - // Debug logs are disabled in silent mode - silent: false, + simpleCommand: { + prefix: '!', + }, +}) - // Configuration for @SimpleCommand - simpleCommand: { - prefix: "!", - }, -}); +bot.once('ready', async () => { + await bot.initApplicationCommands() -bot.once("ready", async () => { - // Make sure all guilds are cached - // await bot.guilds.fetch(); + console.log('Bot started') +}) - // Synchronize applications commands with Discord - await bot.initApplicationCommands(); +bot.on('interactionCreate', (interaction: Interaction) => { + bot.executeInteraction(interaction) +}) - // To clear all guild commands, uncomment this line, - // This is useful when moving from guild commands to global commands - // It must only be executed once - // - // await bot.clearApplicationCommands( - // ...bot.guilds.cache.map((g) => g.id) - // ); - - console.log("Bot started"); -}); - -bot.on("interactionCreate", (interaction: Interaction) => { - bot.executeInteraction(interaction); -}); - -bot.on("messageCreate", async (message: Message) => { - await bot.executeCommand(message); -}); +bot.on('messageCreate', async (message: Message) => { + await bot.executeCommand(message) +}) async function run() { - // The following syntax should be used in the commonjs environment - // - // await importx(__dirname + "/{events,commands}/**/*.{ts,js}"); + await importx(`${dirname(import.meta.url)}/{events,commands}/**/*.{ts,js}`) - // The following syntax should be used in the ECMAScript environment - await importx(`${dirname(import.meta.url)}/{events,commands}/**/*.{ts,js}`); + if (!process.env.BOT_TOKEN) { + throw Error('Could not find BOT_TOKEN in your environment') + } - // Let's start the bot - if (!process.env.BOT_TOKEN) { - throw Error("Could not find BOT_TOKEN in your environment"); - } - - // Log in with your bot token - await bot.login(process.env.BOT_TOKEN); + await bot.login(process.env.BOT_TOKEN) } -void run(); +void run()