Skip to content

Commit

Permalink
✨ Melhorias no sistema de tickets
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashu11-A committed Apr 18, 2024
1 parent 58e4d08 commit 015b29b
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 114 deletions.
88 changes: 87 additions & 1 deletion src/discord/commands/configs/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Command } from '@/discord/base'
import { setSystem } from '@/discord/commands/configs/utils/setSystem'
import { MpModalconfig } from '@/discord/components/config/modals/mpModal'
import { sendEmbed } from '@/discord/components/payments'
import { ticketButtonsConfig } from '@/discord/components/tickets'
import { Database, validarURL } from '@/functions'
import { CustomButtonBuilder, Discord } from '@/functions/Discord'
import {
Expand Down Expand Up @@ -237,6 +238,31 @@ new Command({
type: ApplicationCommandOptionType.String
}
]
},
{
name: 'ticket',
description: '[ 🎫 Ticket ] Configurar o sistema de Tickets',
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: 'panel-embed',
description: '[ 🎫 Ticket ] Envia a embed de configuração.',
required: false,
type: ApplicationCommandOptionType.Channel
},
{
name: 'limit',
description: '[ 🎫 Ticket ] Limita a quantidade tickets por 24h.',
required: false,
type: ApplicationCommandOptionType.Number
},
{
name: 'support-role',
description: '[ 🎫 Ticket ] Definir cargo de suporte.',
required: false,
type: ApplicationCommandOptionType.Role
}
]
}
],
async run (interaction) {
Expand All @@ -249,7 +275,7 @@ new Command({
) { return }

if (!interaction.inCachedGuild()) return
const { options, guildId } = interaction
const { options, guildId, guild } = interaction
try {
switch (options.getSubcommand(true)) {
case 'guild': {
Expand Down Expand Up @@ -542,6 +568,66 @@ new Command({
data: porta
})
}
break
}
case 'ticket': {
await interaction.deferReply({ ephemeral })
const channel = options.getChannel('panel-embed')
const limit = options.getNumber('limit')
const role = options.getRole('support-role')

if (channel !== null) {
const sendChannel = guild?.channels.cache.get(String(channel?.id)) as TextChannel
const embed = new EmbedBuilder({
title: 'Pedir suporte',
description: 'Se você estiver precisando de ajuda clique no botão abaixo',
footer: { text: `Equipe ${interaction.guild?.name}`, iconURL: (interaction?.guild?.iconURL({ size: 64 }) ?? undefined) }
}).setColor('Green')

if (sendChannel !== undefined) {
await sendChannel.send({ embeds: [embed] })
.then(async (msg) => {
await db.messages.set(`${guildId}.ticket.${sendChannel.id}.messages.${msg.id}`, {
id: msg.id,
embed: embed.toJSON()
})
await ticketButtonsConfig(interaction, msg)
await interaction.editReply({
embeds: [
new EmbedBuilder()
.setDescription(`✅ | Mensagem enviada com sucesso ao chat: <#${sendChannel.id}>`)
.setColor('Green')
],
components: [
await Discord.buttonRedirect({
guildId,
channelId: sendChannel.id,
emoji: { name: '🗨️' },
label: 'Ir ao canal'
})
]
})
})
}
}
if (limit !== null) {
await new Database({
interaction,
pathDB: 'config.ticketsLimit',
typeDB: 'guilds'
}).set({
data: limit
})
}
if (role !== null) {
await new Database({
interaction,
pathDB: 'config.ticketRole',
typeDB: 'guilds'
}).set({
data: role.id
})
}
}
}
}
Expand Down
84 changes: 5 additions & 79 deletions src/discord/commands/tickets/ticket.ts
Original file line number Diff line number Diff line change
@@ -1,93 +1,19 @@
import { EmbedBuilder, ApplicationCommandOptionType, ApplicationCommandType, type TextChannel } from 'discord.js'
import { Command } from '@/discord/base'
import { db } from '@/app'
import { TicketButtons, ticketButtonsConfig } from '@/discord/components/tickets'
import { Database, Discord } from '@/functions'
import { TicketButtons } from '@/discord/components/tickets'
import { ApplicationCommandType } from 'discord.js'

new Command({
name: 'ticket',
description: '[ 🎫 Ticket ] Abrir Ticket',
type: ApplicationCommandType.ChatInput,
dmPermission,
options: [
{
name: 'panel-embed',
description: '[ADM] Envia a embed de configuração.',
required: false,
type: ApplicationCommandOptionType.Channel
},
{
name: 'limit',
description: '[ADM] Limita a quantidade tickets por 24h.',
required: false,
type: ApplicationCommandOptionType.Number
}

],
async run (interaction) {
const { guild, guildId, channelId, options } = interaction
const channel = options.getChannel('panel-embed')
const limit = options.getNumber('limit')
const sendChannel = guild?.channels.cache.get(String(channel?.id)) as TextChannel

await interaction.deferReply({ ephemeral: true })
const ticketConstructor = new TicketButtons({ interaction })

if (typeof limit === 'number') {
await new Database({
interaction,
pathDB: 'config.ticketsLimit',
typeDB: 'guilds'
}).set({
data: limit
})
return
}
if (channel === null) {
await ticketConstructor.createTicket({ about: 'Ticket aberto por meio do comando /ticket' })
return
}

if (await Discord.Permission(interaction, 'Administrator')) return

try {
const embed = new EmbedBuilder()
.setTitle('Pedir suporte')
.setDescription('Como Abrir um Ticket:\nPor favor, escolha o tipo de ticket que você deseja abrir.')
.setFooter({ text: `Equipe ${interaction.guild?.name}`, iconURL: (interaction?.guild?.iconURL({ size: 64 }) ?? undefined) })
.setColor('Green')
.setThumbnail(null)
.setImage(null)

if (sendChannel !== undefined) {
await sendChannel.send({ embeds: [embed] })
.then(async (msg) => {
await db.messages.set(`${guildId}.ticket.${channelId}.messages.${msg.id}`, {
id: msg.id,
embed: embed.toJSON()
})
await ticketButtonsConfig(interaction, msg)
await interaction.editReply({
embeds: [
new EmbedBuilder()
.setDescription(`✅ | Mensagem enviada com sucesso ao chat: <#${sendChannel.id}>`)
.setColor('Green')
],
components: [
await Discord.buttonRedirect({
guildId,
channelId: sendChannel.id,
emoji: { name: '🗨️' },
label: 'Ir ao canal'
})
]
})
})
}
} catch (error) {
console.error(error)
return await interaction.editReply({
content: 'Ocorreu um erro!'
})
}
await interaction.deferReply({ ephemeral: true })
await ticketConstructor.createTicket({ about: 'Ticket aberto por meio do comando /ticket' })
}
})
1 change: 0 additions & 1 deletion src/discord/components/SUEE/collectorModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export async function collectorEditModal (options: { interaction: ModalSubmitInt

await db.messages.set(`${guildId}.${type}.${channelId}.messages.${message?.id}.${dataDB}`, messageModal)
await db.messages.set(`${guildId}.${type}.${channelId}.messages.${message?.id}.properties.${button}`, true)
console.log(type, button)
if (type === 'ticket') {
await ticketButtonsConfig(interaction, message)
} else if (type === 'payments') {
Expand Down
1 change: 0 additions & 1 deletion src/discord/components/payments/cart/cartCollectorModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ export default async function cartCollectorModal (options: {
}

default:
console.log(key)
await interaction.deferReply({ ephemeral: true })
await db.payments.set(`${guildId}.process.${channelId}.${modalProperties.db}`, Object.entries(dataInfo)[0][1])
await channel?.messages.fetch(String(message?.id))
Expand Down
1 change: 0 additions & 1 deletion src/discord/components/tickets/collectorSelect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export async function ticketCollectorSelect (options: {
key: string
}): Promise<void> {
const { interaction, key } = options
console.log(key)
const ticketConstructor = new TicketSelects({ interaction })

const customIdHandlers: CustomIdHandlers = {
Expand Down
82 changes: 55 additions & 27 deletions src/discord/components/tickets/functions/buttonsFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { db } from '@/app'
import { CustomButtonBuilder, Discord, createRow } from '@/functions'
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, ComponentType, EmbedBuilder, ModalBuilder, PermissionsBitField, type StringSelectMenuInteraction, TextInputBuilder, type ButtonInteraction, type CacheType, type Collection, type CommandInteraction, type OverwriteResolvable, type Snowflake, type TextChannel } from 'discord.js'
import { ActionRowBuilder, ButtonBuilder, type ButtonInteraction, ButtonStyle, type CacheType, ChannelType, type CommandInteraction, ComponentType, EmbedBuilder, ModalBuilder, type OverwriteResolvable, PermissionsBitField, type StringSelectMenuInteraction, type TextChannel, TextInputBuilder, codeBlock } from 'discord.js'
import { getModalData } from './getModalData'
import { buttonsUsers, ticketButtonsConfig } from './ticketUpdateConfig'

Expand All @@ -13,16 +13,18 @@ export class TicketButtons implements TicketType {
this.interaction = interaction
}

public async createTicket (options: {
public async createTicket ({ about }: {
about: string
}): Promise<void> {
const { about } = options
const { guild, user, guildId } = this.interaction
const { interaction } = this
if (!interaction.inCachedGuild()) return
const { guild, user, guildId } = interaction
const nome = `🎫-${user.id}`
const sendChannel = guild?.channels.cache.find((c) => c.name === nome)
const status: Record<string, boolean | undefined> | null = await db.system.get(`${guild?.id}.status`)
const ticket = await db.guilds.get(`${guild?.id}.ticket`)
const ticketLimit = await db.guilds.get(`${guildId}.config.ticketsLimit`)
const supportRole = await db.guilds.get(`${guild.id}.config.ticketRole`) as string | undefined
const usageDay = await db.system.get(`${guildId}.tickets.${user.id}`) as { date: Date, usage: number } | undefined

if (usageDay !== undefined) {
Expand Down Expand Up @@ -75,18 +77,35 @@ export class TicketButtons implements TicketType {
try {
const permissionOverwrites = [
{
id: guild?.id,
id: guild.id,
deny: [PermissionsBitField.Flags.ViewChannel]
},
{
id: user.id,
allow: [PermissionsBitField.Flags.ViewChannel]
allow: [
PermissionsBitField.Flags.ViewChannel,
PermissionsBitField.Flags.SendMessages,
PermissionsBitField.Flags.AttachFiles,
PermissionsBitField.Flags.AddReactions
]
}
] as OverwriteResolvable[] | Collection<Snowflake, OverwriteResolvable>
] as OverwriteResolvable[]

if (supportRole !== undefined) {
permissionOverwrites.push({
id: supportRole,
allow: [
PermissionsBitField.Flags.ViewChannel,
PermissionsBitField.Flags.SendMessages,
PermissionsBitField.Flags.AttachFiles,
PermissionsBitField.Flags.AddReactions
]
})
}

/* Cria o chat do Ticket */
const category = guild?.channels.cache.find(category => category.type === ChannelType.GuildCategory && category.id === ticket?.category)
const ch = await guild?.channels.create({
const category = guild.channels.cache.find(category => category.type === ChannelType.GuildCategory && category.id === ticket?.category)
const ch = await guild.channels.create({
name: `🎫-${user.id}`,
type: ChannelType.GuildText,
topic: `Ticket do(a) ${user.username}, ID: ${user.id}`,
Expand All @@ -96,10 +115,10 @@ export class TicketButtons implements TicketType {

await this.interaction.editReply({
embeds: [
new EmbedBuilder()
.setTitle(`Olá ${user.username}`)
.setDescription('✅ | Seu ticket foi criado com sucesso!')
.setColor('Green')
new EmbedBuilder({
title: `Olá ${user.username}`,
description: '✅ | Seu ticket foi criado com sucesso!'
}).setColor('Green')
],
components: [
await Discord.buttonRedirect({
Expand All @@ -111,28 +130,37 @@ export class TicketButtons implements TicketType {
]
})
const embed = new EmbedBuilder({
title: `👋 Olá ${interaction.user.displayName}, boas vindas ao seu ticket.`,
fields: [
{ name: '📃・Tipo de Problema/Pedido:', value: about },
{
name: '😁・Solicitante:',
value: `<@${user.id}> | ID: ${user.id}`
},
{
name: '🕗・Aberto em:',
value: '```' + new Date().toLocaleString('pt-BR', { timeZone: 'America/Sao_Paulo' }) + '```'
}
{ name: '📃 Motivo:', value: codeBlock(about) }
],
footer: { text: `Equipe ${guild?.name}`, iconURL: (guild?.iconURL({ size: 64 }) ?? undefined) }
}).setColor('Purple')
footer: { text: `Equipe ${guild?.name} | ${new Date().toLocaleString('pt-BR', { timeZone: 'America/Sao_Paulo' })}`, iconURL: (guild?.iconURL({ size: 64 }) ?? undefined) }
})

const botao = new ActionRowBuilder<ButtonBuilder>().addComponents(
new CustomButtonBuilder({
type: 'Ticket',
permission: 'User',
customId: 'delTicket',
label: 'Fechar Ticket',
emoji: { name: '✖️' },
label: 'Fechar',
emoji: { name: '🔒' },
style: ButtonStyle.Danger
}),
new CustomButtonBuilder({
type: 'Ticket',
permission: 'User',
customId: 'Panel',
label: 'Painel',
emoji: { name: '🖥️' },
style: ButtonStyle.Success
}),
new CustomButtonBuilder({
type: 'Ticket',
permission: 'User',
customId: 'PanelCart',
label: 'Painel vendas',
emoji: { name: '🛒' },
style: ButtonStyle.Primary
})
)
if (ticket?.role !== undefined) {
Expand Down Expand Up @@ -231,7 +259,7 @@ export class TicketButtons implements TicketType {
const clearData = { components: [], embeds: [] }

if (subInteraction.customId === 'embed-cancel-button') {
await subInteraction.editReply({
await subInteraction.update({
...clearData,
embeds: [
new EmbedBuilder()
Expand Down
2 changes: 0 additions & 2 deletions src/discord/components/tickets/functions/modalsFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ export class TicketModals implements TicketType {
public async setConfig (key: string): Promise<void> {
const { fields, guildId, channelId, message, channel } = this.interaction
const { db: dataDB } = getModalData(key)
console.log(fields)
let messageModal = fields.getTextInputValue('content')
console.log('messageModal:', messageModal)

if (messageModal.toLowerCase() === 'vazio') messageModal = ''

Expand Down
Loading

0 comments on commit 015b29b

Please sign in to comment.