tsup as bundler | ticket system init

This commit is contained in:
Danya H 2024-06-06 18:42:04 +01:00
parent 5fa78f5ccd
commit 2b341e5107
16 changed files with 1104 additions and 25 deletions

View File

@ -4,13 +4,11 @@
"private": true,
"license": "MIT",
"type": "module",
"main": "build/main.js",
"main": "build/index.js",
"scripts": {
"dev": "tsx watch src/main.ts",
"build": "tsc",
"build:changelog": "npx @discordx/changelog --src src",
"start": "node build/main.js",
"watch": "nodemon --exec npm run dev --watch src --ext ts"
"dev": "tsx watch src/index.ts",
"build": "tsup",
"start": "node build/index.mjs"
},
"dependencies": {
"@discordx/importer": "^1.3.0",
@ -23,9 +21,11 @@
},
"devDependencies": {
"@types/node": "^20.14.1",
"esbuild-plugin-file-path-extensions": "^2.1.1",
"esbuild-plugin-version-injector": "^1.2.1",
"nodemon": "^3.1.3",
"prettier": "^3.3.0",
"ts-node": "^10.9.2",
"tsup": "^8.1.0",
"tsx": "^4.12.0",
"typescript": "5.4.5"
},

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
import { ButtonComponent, Discord, Slash, SlashOption } from 'discordx'
import {
ActionRowBuilder,
ApplicationCommandOptionType,
ButtonBuilder,
ButtonInteraction,
ButtonStyle,
channelMention,
CommandInteraction,
EmbedBuilder,
GuildMember,
MessageActionRowComponentBuilder,
Role,
ChannelType,
roleMention,
userMention,
} from 'discord.js'
import { db, DBTableEnum } from '../../db'
import { Status } from '../../utils/enums'
@Discord()
export class CreateTicketSystem {
@Slash({
description: 'Create ticket system',
name: 'create-ticket-system',
defaultMemberPermissions: 'Administrator',
})
async createTicketSystem(
@SlashOption({
name: 'role',
description: 'Role to be mentioned on ticket creation',
type: ApplicationCommandOptionType.Role,
required: true,
})
role: Role,
interaction: CommandInteraction,
) {
const pricesChannelId = await db.get(DBTableEnum.PRICE_CHANNEL)
const bannerURL = await db.get(DBTableEnum.BANNER_URL)
const workload = await db.get<Status>(DBTableEnum.WORKLOAD)
await db.set(DBTableEnum.TICKET_ROLE, role.id)
// create ticket embed
const createBtn = new ButtonBuilder()
.setLabel('Open a ticket')
.setEmoji('👉')
.setStyle(ButtonStyle.Success)
.setCustomId('create-btn')
const row =
new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
createBtn,
)
let embedCreate = new EmbedBuilder()
.setTitle(`Create a ticket`)
.setDescription(
`Hey, want to order a design?
Then open a ticket and we'll answer it in a jiffy!
Dear customer, before opening a ticket\n
I strongly recommend that you familiarize yourself with the prices of basic interfaces - ` +
channelMention(pricesChannelId),
)
.setImage(bannerURL)
await interaction.channel?.send({
components: [row],
embeds: [embedCreate],
})
// workload embed
let embedStatus = new EmbedBuilder()
.setTitle(`Workload status by orders`)
.setDescription('**Status:**\n' + getStatusMessage(workload))
const workloadMessage = await interaction.channel?.send({
embeds: [embedStatus],
})
await db.set(DBTableEnum.WORKLOAD_MESSAGE, workloadMessage?.id)
await interaction.reply({
content: 'Created ticket system',
ephemeral: true,
})
}
// listen to button
@ButtonComponent({ id: 'create-btn' })
async createBtn(interaction: ButtonInteraction): Promise<void> {
if (
!(interaction.member instanceof GuildMember) ||
interaction.channel?.type !== ChannelType.GuildText
) {
await interaction.reply('failed')
return
}
const threadChannel = await interaction.channel.threads.create({
name: `${interaction.user.username}`,
type: ChannelType.PrivateThread,
invitable: false,
})
let createdEmbed = new EmbedBuilder()
.setTitle(`${interaction.user.username} opened a ticket`)
.setDescription(
`You successfully opened a ticket. Your ticket: ${channelMention(threadChannel.id)}`,
)
await interaction.reply({ embeds: [createdEmbed], ephemeral: true })
let threadEmbed = new EmbedBuilder()
.setTitle(`${interaction.user.username} opened a ticket`)
.setDescription(
`You successfully opened a ticket. We will be with you soon`,
)
.setFooter({
text: 'You can close ticket by clicking the button below',
})
const ticketRole = await db.get(DBTableEnum.TICKET_ROLE)
const closeBtn = new ButtonBuilder()
.setLabel('Close ticket')
.setStyle(ButtonStyle.Danger)
.setCustomId('close-btn')
const row =
new ActionRowBuilder<MessageActionRowComponentBuilder>().addComponents(
closeBtn,
)
await threadChannel.send({
content: `${userMention(interaction.user.id)} ${roleMention(ticketRole)}`,
embeds: [threadEmbed],
components: [row],
})
const user = await interaction.guild?.members.fetch(interaction.user.id)
const role = await interaction.guild?.roles.fetch(ticketRole)
role?.members.map(
async members => await threadChannel.members.add(members),
)
if (!user) return
await threadChannel.members.add(user)
}
@ButtonComponent({ id: 'close-btn' })
async closeBtn(interaction: ButtonInteraction): Promise<void> {
console.log('close button')
await interaction.channel?.delete()
await interaction.reply('Deleted')
}
}
function getStatusMessage(status: Status | null) {
if (!status) return 'No information provided'
switch (status) {
case Status.AVAILABLE:
return ':green_circle: - Available for orders'
case Status.BUSY:
return ':yellow_circle: - Available for orders, but there may be delays'
case Status.NOT_AVAILABLE:
return ':red_circle: - Currently unavailable for orders'
default:
return 'No information provided'
}
}

View File

@ -4,7 +4,7 @@ import {
CommandInteraction,
TextChannel,
} from 'discord.js'
import { db, DBTableEnum } from '../../db.ts'
import { db, DBTableEnum } from '../../db'
@Discord()
export class SetFeedbackChannel {

View File

@ -4,7 +4,7 @@ import {
CommandInteraction,
TextChannel,
} from 'discord.js'
import { db, DBTableEnum } from '../../db.ts'
import { db, DBTableEnum } from '../../db'
@Discord()
export class SetFeedbackChannel {

View File

@ -4,7 +4,7 @@ import {
CommandInteraction,
TextChannel,
} from 'discord.js'
import { db, DBTableEnum } from '../../db.ts'
import { db, DBTableEnum } from '../../db'
@Discord()
export class SetOrderChannel {

View File

@ -4,7 +4,7 @@ import {
CommandInteraction,
TextChannel,
} from 'discord.js'
import { db, DBTableEnum } from '../../db.ts'
import { db, DBTableEnum } from '../../db'
@Discord()
export class SetPortfolioChannel {

View File

@ -4,7 +4,7 @@ import {
CommandInteraction,
TextChannel,
} from 'discord.js'
import { db, DBTableEnum } from '../../db.ts'
import { db, DBTableEnum } from '../../db'
@Discord()
export class SetPriceChannel {

View File

@ -1,12 +1,7 @@
import { Discord, Slash, SlashChoice, SlashOption } from 'discordx'
import { ApplicationCommandOptionType, CommandInteraction } from 'discord.js'
import { db, DBTableEnum } from '../../db.js'
enum Status {
AVAILABLE = 'AVAILABLE',
BUSY = 'BUSY',
NOT_AVAILABLE = 'NOT_AVAILABLE',
}
import { db, DBTableEnum } from '../../db'
import { Status } from '../../utils/enums.ts'
@Discord()
export class SetStatus {

View File

@ -5,7 +5,7 @@ import {
Role,
TextChannel,
} from 'discord.js'
import { db, DBTableEnum } from '../../db.ts'
import { db, DBTableEnum } from '../../db'
@Discord()
export class SetWelcomeChannel {

View File

@ -4,7 +4,7 @@ import {
CommandInteraction,
EmbedBuilder,
} from 'discord.js'
import { db, DBTableEnum } from '../db.ts'
import { db, DBTableEnum } from '../db'
@Discord()
export class Feedback {

View File

@ -4,11 +4,12 @@ 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',
MAKE_AN_ORDER_CHANNEL = 'MAKE_AN_ORDER_CHANNEL',
PRICE_CHANNEL = 'PRICE_CHANNEL',
BANNER_URL = 'BANNER_URL',
WORKLOAD = 'STATUS',
WORKLOAD = 'WORKLOAD',
WORKLOAD_MESSAGE = 'WORKLOAD_MESSAGE',
TICKET_ROLE = 'TICKET_ROLE',
}

View File

@ -1,6 +1,6 @@
import { ArgsOf, Discord, On } from 'discordx'
import { EmbedBuilder, channelMention, userMention } from 'discord.js'
import { db, DBTableEnum } from '../db.ts'
import { db, DBTableEnum } from '../db'
@Discord()
export class GuildMemberAdd {

View File

@ -41,7 +41,7 @@ bot.on('messageCreate', async (message: Message) => {
})
async function run() {
await importx(`${dirname(import.meta.url)}/{events,commands}/**/*.{ts,js}`)
await importx(`${dirname(import.meta.url)}/{events,commands}/**/*.{ts,mjs}`)
if (!process.env.BOT_TOKEN) {
throw Error('Could not find BOT_TOKEN in your environment')

5
src/utils/enums.ts Normal file
View File

@ -0,0 +1,5 @@
export enum Status {
AVAILABLE = 'AVAILABLE',
BUSY = 'BUSY',
NOT_AVAILABLE = 'NOT_AVAILABLE',
}

35
tsup.config.ts Normal file
View File

@ -0,0 +1,35 @@
import { esbuildPluginFilePathExtensions } from 'esbuild-plugin-file-path-extensions'
import { esbuildPluginVersionInjector } from 'esbuild-plugin-version-injector'
import { defineConfig, type Options } from 'tsup'
const baseOptions: Options = {
clean: true,
entry: ['src/**/*.ts'],
dts: false,
minify: true,
skipNodeModulesBundle: true,
sourcemap: false,
target: 'es2021',
tsconfig: 'tsconfig.json',
keepNames: true,
esbuildPlugins: [
esbuildPluginVersionInjector(),
esbuildPluginFilePathExtensions(),
],
treeshake: true,
}
export default [
// defineConfig({
// ...baseOptions,
// outDir: 'dist/cjs',
// format: 'cjs',
// outExtension: () => ({ js: '.cjs' }),
// }),
defineConfig({
...baseOptions,
outDir: 'build',
format: 'esm',
outExtension: () => ({ js: '.mjs' }),
}),
]